package com.codi.bus.core.service.impl;

import com.codi.base.exception.BaseAppException;
import com.codi.base.exception.ExceptionHandler;
import com.codi.base.util.*;
import com.codi.bus.constant.GlobalConstant;
import com.codi.bus.constant.RuleConstant;
import com.codi.bus.core.dao.*;
import com.codi.bus.core.domain.*;
import com.codi.bus.core.domain.ext.UserExt;
import com.codi.bus.core.resultModel.*;
import com.codi.bus.core.service.*;
import com.codi.bus.core.service.model.*;
import com.codi.bus.core.service.organ.OrganClientService;
import com.codi.bus.core.service.organ.OrganMineService;
import com.codi.bus.core.service.organ.OrganProfileService;
import com.codi.bus.core.service.util.BizUtils;
import com.codi.bus.core.service.util.ObjectCreator;
import com.codi.bus.core.vo.OrganProfileVo;
import com.codi.bus.core.vo.OrganProfileVoNew;
import com.codi.bus.core.vo.UserBankVo;
import com.codi.bus.core.vo.UserProfileVo;
import com.codi.bus.exception.BaseException;
import com.codi.bus.exception.InterfaceFieldNoFindExcepiton;
import com.codi.bus.exception.SystemDBException;
import com.codi.fcloud.ufx.HsResponseUtil;
import com.codi.fcloud.ufx.HsUtil;
import com.codi.fcloud.ufx.constant.CheckFlag;
import com.codi.fcloud.ufx.constant.HSOutputParameterNames;
import com.codi.fcloud.ufx.constant.HsConst;
import com.codi.fcloud.ufx.hssale.acco.ClearTradePassword;
import com.codi.message.constant.ErrorConst;
import com.codi.message.constant.ErrorConstant;
import com.codi.message.util.MessageUtil;
import com.codi.superman.base.service.SysDBService;
import com.codi.trade.dto.FundAcctOpenDto;
import com.codi.trade.service.*;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.UUID;

@Service("userService")
@Transactional
@SuppressWarnings("Duplicates")
public class UserServiceImpl implements UserService {

    private static final Logger logger = LoggerFactory.getLogger(UserServiceImpl.class);

    @Resource(name = "userDao")
    private UserDao userDao;

    @Resource(name = "userBankDao")
    private UserBankDao userBankDao;

    @Resource(name = "userSessionDao")
    private UserSessionDao userSessionDao;

    @Resource(name = "organAgentDao")
    private OrganAgentDao organAgentDao;

    @Resource(name = "userSessionHistoryDao")
    private UserSessionHistoryDao userSessionHistoryDao;

    @Resource(name = "verifyDao")
    private VerifyDao verifyDao;

    @Resource(name = "cardBinDao")
    private CardBinDao cardBinDao;

    @Resource(name = "transactionDao")
    private TransactionDao transactionDao;

    @Resource(name = "paySignContractSmsService")
    private PaySignContractSmsService paySignContractSmsService;

    @Resource(name = "fundacctDirectOpenAcctService")
    private FundacctDirectOpenAcctService fundacctDirectOpenAcctService;

    @Resource(name = "loginAcctService")
    private LoginAcctService loginAcctService;

    @Resource(name = "tradeAccountAddAcctService")
    private TradeAccountAddAcctService tradeAccountAddAcctService;

    @Resource(name = "mainTransAccountModAcctService")
    private MainTransAccountModAcctService mainTransAccountModAcctService;

    @Resource(name = "transAccountCloseAcctService")
    private TransAccountCloseAcctService transAccountCloseAcctService;

    @Resource(name = "queryService")
    private QueryService queryService;

    @Resource(name = "loginAcctService")
    private LoginAcctService loginAcct;

    @Resource(name = "accountQueryService")
    private AccountQueryService accountQuery;

    @Resource(name = "clearTradePassword")
    private ClearTradePassword clearTradePassword;

    @Resource(name = "lookupDao")
    private LookupDao lookupDao;

    @Autowired
    private UserProfileService userProfileService;

    @Autowired
    private OrganProfileService organProfileService;

    @Autowired
    private ClientService clientService;

    @Autowired
    private SysDBService sysDBService;

    @Autowired
    private SMSSimpleService smsSimpleService;

    @Autowired
    private PaperInfoService paperInfoService;

    @Autowired
    private OrganBankDao organBankDao;

    @Autowired
    private OrganClientService organClientService;

    @Autowired
    private OrganMineService organMineService;

    /*
     * 解绑银行卡（第一种情况不能解绑银行卡）
     * 解绑银行卡的首要条件是该卡处于3无情况（无在途申请，无持有份额，无在途资金或持有资金，如果客户赎回之后，钱处于尚未划款状态，也无法解绑） 1
     * 只有一个主交易账号（就是第一次开户的账号），主交易账号对应第一张卡 使用销基金账号(对应接口TA帐号销户），需要TA确认，销户后客户编号也会销户
     *
     * 2有主卡（主交易账号），有副卡（非主交易账号）销副卡
     *
     * 使用销交易账号(对应接口交易帐号销户）
     *
     * 3有主卡（主交易账号），有副卡（非主交易账号）销主卡
     * 先使用变更主交易账号(对应接口变更主交易账号），将副卡变为主卡，使用销交易账号(对应接口交易帐号销户）
     */
    // 不需要传TA账号
    @Override
    public BaseResult repalceAndCloseTradeAccount(long userId, String password, String bankCard, String capitalMode, Long profileId)
        throws BaseException {
        logger.info("repalceAndCloseTradeAccount - userId={}, bankCard={}, capitalMode={}", userId, bankCard, capitalMode);

        BaseResult result = new BaseResult();
        try {

            String clientId;
            if (profileId != null) {
                OrganProfile organProfile = organProfileService.qryByProfileId(profileId);
                clientId = organProfile.getExternalClientId();
                if (organProfile == null || StringUtil.isEmpty(clientId)) {
                    result.setSuccess(false);
                    result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
                    result.setErrorCode(ErrorConstant.ERROR_NO_ACCOUNT);
                    return result;
                }
            } else {
                User user = userDao.getEntity(userId);
                clientId = user.getExternalClientId();
                // 获取用户信息
                if (user == null || StringUtil.isEmpty(clientId)) {
                    result.setSuccess(false);
                    result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
                    result.setErrorCode(ErrorConstant.ERROR_NO_ACCOUNT);
                    return result;
                }
            }

            String tradeAccount;
            // 获取此银行卡的交易账号信息
            if (profileId != null) {
                OrganBank organBank = organBankDao.getByProfileIdAndBankNo(profileId, bankCard);
                if (organBank == null || StringUtil.isEmpty(organBank.getExternalTradeAccount())) {
                    result.setSuccess(false);
                    result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
                    result.setErrorCode(ErrorConstant.ERROR_NO_BANK_CARD_FIND);
                    return result;
                }
                tradeAccount = organBank.getExternalTradeAccount();

            } else {

                UserBank userBank = userBankDao.getEntityByBankNo(userId, bankCard, capitalMode);
                if (userBank == null || StringUtil.isEmpty(userBank.getExternalTradeAccount())) {
                    result.setSuccess(false);
                    result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
                    result.setErrorCode(ErrorConstant.ERROR_NO_BANK_CARD_FIND);
                    return result;
                }
                tradeAccount = userBank.getExternalTradeAccount();
            }


            // 查询此用户的所有银行卡信息
            BaseListResult baseListResult = queryService.queryAccountBanks("", clientId, "",
                GlobalConstant.MAX_REQUEST_NUM, 1, 1, "1");
            if (!baseListResult.getSuccess()) {
                result.setSuccess(false);
                result.setErrorType(baseListResult.getErrorType());
                result.setErrorCode(baseListResult.getErrorCode());
                return result;
            }

            // 获取主交易账号
            String mainAccount = "";
            String taAccount = "";
            List<BankModel> accounts = ((BankListResult) baseListResult).getBanks();
            if (accounts == null) {
                result.setSuccess(false);
                result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
                result.setErrorCode(ErrorConstant.ERROR_NO_BANK_CARD_FIND);
                return result;
            }
            for (BankModel accountModel : accounts) {
                if (accountModel.getMainAccountFlag().equals(GlobalConstant.MAIN_ACCOUNT_FLAG_YES)) {
                    mainAccount = accountModel.getTradeAccount();
                }
                // 获取TA账号
                if (accountModel.getTradeAccount().equals(tradeAccount)) {
                    taAccount = accountModel.getTaAccount();
                }
            }

            // 未找到主交易账号的话直接报错返回
            if (StringUtil.isEmpty(mainAccount)) {
                result.setSuccess(false);
                result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
                result.setErrorCode(ErrorConstant.ERROR_NO_MAIN_ACCOUNT_FIND);
                return result;
            }

            logger.info("repalceAndCloseTradeAccount - main account={}, closing account={}, TA account={}", mainAccount,
                tradeAccount, taAccount);

            // 待解绑的银行卡是主卡， 先变更主交易账号
            if (tradeAccount.equals(mainAccount)) {

                // 去找到一个新的主交易账号
                String newTradeAccount = "";
                String newTaAccount = "";
                for (BankModel bank : accounts) {
                    if (bank.getTradeAccount().equals(mainAccount)) {
                        continue;
                    } else if (bank.getTradeAccountStatus().equals(GlobalConstant.TRADE_ACCOUNT_STATUS_WORKING)) {
                        newTradeAccount = bank.getTradeAccount();
                        newTaAccount = bank.getTaAccount();
                        break;
                    }
                }
                // 如果只有主交易账号，则不能销户
                if (StringUtil.isEmpty(newTradeAccount)) {
                    result.setSuccess(false);
                    result.setErrorType(GlobalConstant.ERROR_TYPE_BUSINESS);
                    result.setErrorCode(ErrorConstant.ERROR_CAN_NOT_CLOSE);
                    return result;
                }

                // 调用接口变更主交易账号
                // 不需要传TA账号
                result = replaceAccount(newTradeAccount, newTaAccount, password, tradeAccount);
                if (result.getSuccess() == false) {
                    return result;
                }
            }

            // 调用接口解绑银行卡
            // 不需要传TA账号
            result = closeAccount(tradeAccount, "", password);
            if (result.getSuccess() == false) {
                return result;
            }

            // 更新银行卡状态
            // TODO 不能马上更新状态，因为解绑是否成功是异步的，解绑需要TA确认的，

            result.setSuccess(true);
            return result;
        } catch (BaseException baseException) {
            throw baseException;
        } catch (Exception e) {
            ExceptionUtil.logError(logger, "repalceAndCloseTradeAccount - Exception:", e);
            throw new SystemDBException("repalceAndCloseTradeAccount Failure!", e);
        }
    }

    // 交易账号销户一般用于销非主交易账号，就是解绑增开的银行卡
    @Override
    public BaseResult closeAccount(String tradeAccount, String taAccount, String password) throws BaseException {

        logger.info("closeAccount - tradeAccount={}, taAccount={}", tradeAccount, taAccount);
        try {
            BaseResult result = new BaseResult();

            // 解绑银行卡 - 交易帐号销户
            Map<String, Object> map = transAccountCloseAcctService.closeAccount(tradeAccount, taAccount,
                MD5.MD5Encode(password));

            if (!HsResponseUtil.isOperationOk(map)) {
                String errorInfo = map.get(HSOutputParameterNames.ERROR_INFO).toString();
                result.setSuccess(false);
                result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
                result.setErrorCode(ErrorConstant.ERROR_HUNDSUNAPI_WRONG);
                result.setErrorMessage(errorInfo);
                logger.error("closeAccount - closeAccount - error info:" + errorInfo);
            } else {
                result.setSuccess(true);
            }

            // 插入交易记录流水
            Transaction transaction = ObjectCreator.createTransaction(map);
            // 不管成功或失败，都插入交易流水
            transactionDao.add(transaction);

            return result;
        } catch (BaseException baseException) {
            throw baseException;
        } catch (Exception exception) {
            ExceptionUtil.logError(logger, "closeAccount - Exception:", exception);
            throw new SystemDBException("closeAccount Failure!", exception);
        }
    }

    // 变更朱交易账号是指客户想要解绑开户时的银行卡，可以变更主交易账号到增开的交易账号，变更需要指交易账户三无状态
    @Override
    public BaseResult replaceAccount(String newMainAccount, String taAccount, String password,
                                     String originalMainAccount) throws BaseException {

        logger.info("replaceAccount: newTradeAccount={}, TA={}, originalTradeAccount={}",
            newMainAccount, taAccount, originalMainAccount);
        try {
            BaseResult result = new BaseResult();

            // 需要先调用更换主交易账号
            Map<String, Object> map = mainTransAccountModAcctService.replace(newMainAccount, taAccount,
                MD5.MD5Encode(password), originalMainAccount);

            if (!HsResponseUtil.isOperationOk(map)) {
                String errorInfo = map.get(HSOutputParameterNames.ERROR_INFO).toString();
                result.setSuccess(false);
                result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
                result.setErrorCode(ErrorConstant.ERROR_HUNDSUNAPI_WRONG);
                result.setErrorMessage(errorInfo);
                logger.error("replaceAccount - replace - error info:" + errorInfo);
            } else {
                result.setSuccess(true);
            }

            // 插入交易记录流水
            Transaction transaction = ObjectCreator.createTransaction(map);
            // 不管成功或失败，都插入交易流水
            transactionDao.add(transaction);

            return result;
        } catch (BaseException baseException) {
            throw baseException;
        } catch (Exception e) {
            ExceptionUtil.logError(logger, "replaceAccount - Exception:", e);
            throw new SystemDBException("replaceAccount Failure!", e);
        }
    }

    /**
     * 注册机构用户
     *
     * @param entity
     * @return
     * @throws BaseException
     */
    @Override
    public User registerOrganAccount(User entity) throws BaseException {

        Preconditions.checkNotNull(entity, "Parameter 'User' Is Null!");

        logger.info("registerAccount - mobile={}", entity.getUserMobile());


        Verify verifyEntity = new Verify();
        verifyEntity.setBizCode(GlobalConstant.SMS_BIZ_CODE_VERIFY);
        verifyEntity.setMobile(entity.getUserMobile());
        // 删除验证码
        verifyDao.deleteVerifyByMobileAndBizCode(verifyEntity);

        OrganAgent agent = organAgentDao.getEntityByMobile(entity.getUserMobile());

        User user = new User();

        if (agent != null) {
            user.setIsOrg(false);
        } else {
            user.setIsOrg(true);
        }


        user.setUserFrom(GlobalConstant.USER_FROM_APP);
        user.setUserState(User.USER_STATE_MOBILE);
        user.setUserMobile(entity.getUserMobile());
        user.setLoginPassword(MD5.MD5Encode(entity.getLoginPassword())); // 对登录密码加密

        userDao.add(user);

        return user;
    }

    @Override
    public BaseResult addOrganProfile(Long userId, OrganProfileVo organProfileVo, UserBankVo userBankVo) throws BaseAppException {
        Preconditions.checkNotNull(userId);
        Preconditions.checkNotNull(organProfileVo);
        Preconditions.checkNotNull(userBankVo);

        OrganProfile record = organProfileService.qryByUserId(userId);

        if (record != null) {
            ExceptionHandler.publish(ErrorConst.ORGAN_BASIC_PROFILE_IS_EXIST);
        }

        OrganProfile organProfile = new OrganProfile();
        org.springframework.beans.BeanUtils.copyProperties(organProfileVo, organProfile, "profileId");

        //
        AccountOpenResult result = new AccountOpenResult();

        //
        User user = userDao.getEntity(userId); // 肯定是存在的

        logger.info("userId={},mobile={}", user.getUserId(), user.getUserMobile());
        logger.info("bank info={}", userBankVo);

        // 校验验证执照号唯一性
        boolean exist = organProfileService.checkBizLicenseExist(organProfile.getBusinessLicence());
        if (exist) {
            ExceptionHandler.publish(ErrorConst.ORGAN_BIZ_LICENCE_EXIST);
        }

        //三证合一
        if (organProfile.getThreeInOne()) {
            organProfile.setOrganCode(organProfile.getBusinessLicence());
            organProfile.setTaxRegister(organProfile.getBusinessLicence());
        }

        if (organProfile.getBusinessLicenceLongEffective()) {
            organProfile.setBusinessLicenceExpireDate(DateUtil.getMaxDate());
        }
        if (organProfile.getInstreprIdNoLongEffective()) {
            organProfile.setInstreprIdNoExpireDate(DateUtil.getMaxDate());
        }


        UserBank bankEntity = new UserBank();
        org.springframework.beans.BeanUtils.copyProperties(userBankVo, bankEntity, "userBankId");
        bankEntity.setCapitalMode(GlobalConstant.CAPTIAL_MODE_K);
        bankEntity.setUserId(user.getUserId());

        // 获取恒生银行编号
        String bankHSCode = "";
        List<Lookup> lookups = lookupDao.getLookupByType(RuleConstant.RULE_LOOKUP_TYPE_HSBANK);
        for (Lookup lookup : lookups) {
            if (lookup.getComponentValue().equals(bankEntity.getBankCode())) {
                bankHSCode = lookup.getRuleValue();
                break;
            }
        }
        if (StringUtil.isEmpty(bankHSCode)) {
            result.setSuccess(false);
            result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
            result.setErrorCode(ErrorConstant.ERROR_NO_BANK_CARD_FIND);
            result.setErrorMessage(MessageUtil.getErrorMessage(ErrorConstant.ERROR_NO_BANK_CARD_FIND,
                ErrorConstant.PLACEHOLDER_FIELD_NO_FIND_FIELD, bankEntity.getBankCode()));
            return result;
        }


        // 调用开户接口
        FundAcctOpenDto dto = new FundAcctOpenDto();

        dto.setClient_name(HsUtil.getClientName(organProfile.getCompanyName()));
        dto.setClient_full_name(HsUtil.getClientFullName(organProfile.getCompanyName()));

        dto.setId_kind_gb(HsConst.ID_KIND_GB_BUSINESS_LICENSE);
        dto.setId_no(organProfile.getBusinessLicence());
        dto.setPassword(MD5.MD5Encode(organProfileVo.getTradePassword()));
        dto.setAddress(organProfile.getAddress());
        dto.setMobile_tel(user.getUserMobile());
        dto.setHome_tel(user.getUserMobile());

        dto.setBank_no(bankHSCode);
        dto.setBank_name(bankEntity.getBankName());
        dto.setBank_account(bankEntity.getUserBankNo());
        dto.setBank_account_name(organProfile.getCompanyName());
        dto.setBank_account_name_long(bankEntity.getBankAccountName());

//        dto.setFund_card(bankEntity.getExternalProtocolNo());
        dto.setCapital_mode(bankEntity.getCapitalMode());
        dto.setRemittance_no("01");


        dto.setCust_type(GlobalConstant.CUST_TYPE_ORGANIZATION); // 机构
        dto.setCompany_name(organProfile.getCompanyName());
        dto.setTax_register(organProfile.getTaxRegister());
        dto.setBusiness_range(organProfile.getBusinessRange());

        dto.setInstrepr_name(organProfile.getInstreprName());
        dto.setInstrepr_id_no(organProfile.getInstreprIdNo());
        dto.setInstrepr_id_enddate(DateUtil.format(organProfile.getInstreprIdNoExpireDate(), "yyyyMMdd"));
        dto.setReg_address(organProfile.getAddress());
        dto.setTrade(organProfile.getTrade());
        dto.setCor_property(organProfile.getCorProperty());
        dto.setReg_capital(organProfile.getRegCapital());
        dto.setAddress(organProfile.getAddress());
        dto.setZipcode(organProfile.getPostcode());
        dto.setHome_tel(user.getUserMobile());

        // 经办人
        dto.setContact_name(organProfile.getContactName());
        dto.setContact_tel(organProfile.getContactTel());
        dto.setContact_id_no(organProfile.getContactIdNo());

        dto.setBeneficiary(organProfile.getBeneficiary());// 实际受益人
        dto.setHolding_name(organProfile.getOwner());//实际控制人
        dto.setBranchbank(bankEntity.getBranchbank());//银行联号

        Map<String, Object> map = fundacctDirectOpenAcctService.openAcct(dto);

        if (!HsResponseUtil.isOperationOk(map)) {
            String errorInfo = map.get(HSOutputParameterNames.ERROR_INFO).toString();
            result.setSuccess(false);
            result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
            result.setErrorCode(ErrorConstant.ERROR_HUNDSUNAPI_WRONG);
            result.setErrorMessage(errorInfo);
            logger.error("open org Account errr info:{}", errorInfo);
        } else {
            // 只有成功时才有交易账号返回
            String externalTradeAccount = map.get(HSOutputParameterNames.TRADE_ACCO).toString();
            // 返回成功
            result.setSuccess(true);


            // 插入用户银行表
            bankEntity.setExternalTradeAccount(externalTradeAccount);
            bankEntity.setUserBankOwner(organProfile.getCompanyName());
            bankEntity.setUserBankMobile(user.getUserMobile());
            bankEntity.setExternalProtocolNo(null);
            userBankDao.add(bankEntity);

            // 更新用户表
            user.setExternalClientId(map.get(HSOutputParameterNames.CLIENT_ID).toString());
            user.setUserName(organProfile.getCompanyName());
            // 添加用户身份证，法人身份证信息
            user.setUserCard(organProfile.getInstreprIdNo());
            userDao.updateUser(user);

            // 添加机构扩展资料
            //添加交易报备号码
            organProfile.setUserId(user.getUserId());
            organProfile.setState(GlobalConstant.ORGAN_STATE_AUDITING);
            organProfile.setTradeReportTel(organProfileVo.getTradeReportTel().trim());

            organProfileService.addOrUpdateByProfileId(organProfile);

            logger.info("add user profile info");
        }

        // TODO 需要考虑一种情况，即最后更新交易账号失败，但恒生开户接口已调用成功，需要回滚？
        // 插入交易记录流水
        Transaction transaction = ObjectCreator.createTransaction(map);
        // 不管成功或失败，都插入交易流水
        transactionDao.add(transaction);

        // 设置用户信息
        user = userDao.getEntity(user.getUserId());

        UserModel model = new UserModel();
        model.setIsOrg(true);
        model.setUserId(user.getUserId());
        model.setMobile(user.getUserMobile());
        model.setUserName(user.getUserName());


        result.setUser(model);

        return result;
    }

    @Override
    @Transactional
    public BaseResult addOrganProfileNew(Long userId, OrganProfileVoNew organProfileVoNew, UserBankVo userBankVo) throws BaseAppException {
        Preconditions.checkNotNull(userId);
        Preconditions.checkNotNull(organProfileVoNew);
        Preconditions.checkNotNull(userBankVo);

//        OrganProfile record = organProfileService.qryByUserId(userId);
////
////        if (record != null) {
////            ExceptionHandler.publish(ErrorConst.ORGAN_BASIC_PROFILE_IS_EXIST);
////        }

        OrganProfile organProfile = new OrganProfile();
        org.springframework.beans.BeanUtils.copyProperties(organProfileVoNew, organProfile, "profileId");

        //
        AccountOpenResult result = new AccountOpenResult();

        //
        User user = userDao.getEntity(userId); // 肯定是存在的

        logger.info("userId={},mobile={}", user.getUserId(), user.getUserMobile());
        logger.info("bank info={}", userBankVo);

        // 校验验证执照号唯一性
        boolean exist = organProfileService.checkBizLicenseExist(organProfile.getBusinessLicence());
        if (exist) {
            ExceptionHandler.publish(ErrorConst.ORGAN_BIZ_LICENCE_EXIST);
        }


        organProfile.setOrganCode(organProfile.getBusinessLicence());
        organProfile.setTaxRegister(organProfile.getBusinessLicence());

        organProfile.setBusinessLicenceExpireDate(DateUtil.getMaxDate());


        organProfile.setInstreprIdNoExpireDate(DateUtil.getMaxDate());


        UserBank bankEntity = new UserBank();
        org.springframework.beans.BeanUtils.copyProperties(userBankVo, bankEntity, "userBankId");
        bankEntity.setCapitalMode(GlobalConstant.CAPTIAL_MODE_K);
        bankEntity.setUserId(user.getUserId());

        OrganProfile profile = null;

        // 获取恒生银行编号
        String bankHSCode = "";
        List<Lookup> lookups = lookupDao.getLookupByType(RuleConstant.RULE_LOOKUP_TYPE_HSBANK);
        for (Lookup lookup : lookups) {
            if (lookup.getComponentValue().equals(bankEntity.getBankCode())) {
                bankHSCode = lookup.getRuleValue();
                break;
            }
        }
        if (StringUtil.isEmpty(bankHSCode)) {
            result.setSuccess(false);
            result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
            result.setErrorCode(ErrorConstant.ERROR_NO_BANK_CARD_FIND);
            result.setErrorMessage(MessageUtil.getErrorMessage(ErrorConstant.ERROR_NO_BANK_CARD_FIND,
                ErrorConstant.PLACEHOLDER_FIELD_NO_FIND_FIELD, bankEntity.getBankCode()));
            return result;
        }


        // 调用开户接口
        FundAcctOpenDto dto = new FundAcctOpenDto();

        dto.setClient_name(HsUtil.getClientName(organProfile.getCompanyName()));
        dto.setClient_full_name(HsUtil.getClientFullName(organProfile.getCompanyName()));

        dto.setId_kind_gb(HsConst.ID_KIND_GB_BUSINESS_LICENSE);
        dto.setId_no(organProfile.getBusinessLicence());
        dto.setPassword(MD5.MD5Encode(organProfileVoNew.getTradePassword()));
        dto.setAddress(organProfile.getAddress());
        dto.setMobile_tel(user.getUserMobile());
        dto.setHome_tel(user.getUserMobile());

        dto.setBank_no(bankHSCode);
        dto.setBank_name(bankEntity.getBankBranchName());
        dto.setBank_account(bankEntity.getUserBankNo());
        dto.setBank_account_name(organProfile.getCompanyName());
        dto.setBank_account_name_long(bankEntity.getBankAccountName());

//        dto.setFund_card(bankEntity.getExternalProtocolNo());
        dto.setCapital_mode(bankEntity.getCapitalMode());
        dto.setRemittance_no("01");


        dto.setCust_type(GlobalConstant.CUST_TYPE_ORGANIZATION); // 机构
        dto.setCompany_name(organProfile.getCompanyName());
        dto.setTax_register(organProfile.getTaxRegister());
        dto.setBusiness_range(organProfile.getBusinessRange());

        dto.setInstrepr_name(organProfile.getInstreprName());
        dto.setInstrepr_id_no(organProfile.getInstreprIdNo());
        dto.setInstrepr_id_enddate(DateUtil.format(organProfile.getInstreprIdNoExpireDate(), "yyyyMMdd"));
        dto.setReg_address(organProfile.getAddress());
        dto.setTrade(organProfile.getTrade());
        dto.setCor_property(organProfile.getCorProperty());
        dto.setReg_capital(organProfile.getRegCapital());
        dto.setAddress(organProfile.getAddress());
        dto.setZipcode(organProfile.getPostcode());
        dto.setHome_tel(user.getUserMobile());

        // 经办人
        dto.setContact_name(organProfile.getContactName());
        dto.setContact_tel(organProfile.getContactTel());
        dto.setContact_id_no(organProfile.getContactIdNo());

        dto.setBeneficiary(organProfile.getBeneficiary());// 实际受益人
        dto.setHolding_name(organProfile.getOwner());//实际控制人
        dto.setBranchbank(bankEntity.getBranchbank());//银行联号

        Map<String, Object> map = fundacctDirectOpenAcctService.openAcct(dto);

        if (!HsResponseUtil.isOperationOk(map)) {
            String errorInfo = map.get(HSOutputParameterNames.ERROR_INFO).toString();
            result.setSuccess(false);
            result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
            result.setErrorCode(ErrorConstant.ERROR_HUNDSUNAPI_WRONG);
            result.setErrorMessage(errorInfo);
            logger.error("open org Account errr info:{}", errorInfo);
        } else {
            // 只有成功时才有交易账号返回
            String externalTradeAccount = map.get(HSOutputParameterNames.TRADE_ACCO).toString();
            // 返回成功
            result.setSuccess(true);

            // 插入用户银行表
            bankEntity.setExternalTradeAccount(externalTradeAccount);
            bankEntity.setUserBankOwner(organProfile.getCompanyName());
            bankEntity.setUserBankMobile(user.getUserMobile());
            bankEntity.setExternalProtocolNo(null);
//            userBankDao.add(bankEntity);

            organProfile.setExternalClientId(map.get(HSOutputParameterNames.CLIENT_ID).toString());
            // 更新用户表
            //user.setExternalClientId(map.get(HSOutputParameterNames.CLIENT_ID).toString());
            //user.setUserName(organProfile.getCompanyName());
            // 更新用户信息，法人身份证
            if (StringUtils.isBlank(user.getUserCard())) {
                user.setUserCard(organProfile.getInstreprIdNo());
            }
            userDao.updateUser(user);

            // 添加机构扩展资料
            //添加交易报备号码


            OrganAgent agent = organAgentDao.getEntityByMobile(organProfileVoNew.getContactTel().trim());
            if (!Strings.isNullOrEmpty(organProfileVoNew.getContactIdNo()) || !Strings.isNullOrEmpty(organProfileVoNew.getContactName()) || !Strings.isNullOrEmpty(organProfileVoNew.getContactTel())) {
                if (agent == null) {
                    agent = new OrganAgent();
                    agent.setCreateUserId(userId);
                    agent.setOrganAgentIdcard(organProfileVoNew.getContactIdNo());
                    agent.setOrganAgentMobile(organProfileVoNew.getContactTel());
                    agent.setOrganAgentName(organProfileVoNew.getContactName());
                    agent.setCreateTime(new Date());
                    organAgentDao.insertOne(agent);
                }
            }

            organProfile.setUserId(user.getUserId());
            organProfile.setState(GlobalConstant.ORGAN_STATE_AUDITING);
            organProfile.setOrganAgentId(agent.getAgentId());

//            organProfile.setTradeReportTel(organProfileVo.getTradeReportTel().trim());

            profile = organProfileService.addOrUpdateByProfileId(organProfile);

            logger.info("add user profile info");

            OrganBank organBank = new OrganBank();
            organBank.setUserId(bankEntity.getUserId());
            organBank.setProfileId(profile.getProfileId());
            organBank.setUbBankName(bankEntity.getBankName());
            organBank.setUbBankCode(bankEntity.getBankCode());
            // 添加恒生银行编号
            organBank.setUbBankNo(bankHSCode);
            organBank.setAuditStatus(1);
            organBank.setUbOrganBankNo(bankEntity.getUserBankNo());
            organBank.setUbOrganBankOwner(bankEntity.getUserBankOwner());
            organBank.setUbBranchbank(bankEntity.getBranchbank());
            organBank.setUbBankBranchName(bankEntity.getBankBranchName());
            organBank.setUbCapitalMode(bankEntity.getCapitalMode());
            organBank.setExternalTradeAccount(bankEntity.getExternalTradeAccount());
            organBank.setTradePassword(MD5.MD5Encode(organProfileVoNew.getTradePassword()));
            organBank.setCreateTime(new Date());
            organBank.setUserId(userId);
            organBankDao.insertOne(organBank);
        }

        // TODO 需要考虑一种情况，即最后更新交易账号失败，但恒生开户接口已调用成功，需要回滚？
        // 插入交易记录流水
        Transaction transaction = ObjectCreator.createTransaction(map);
        // 不管成功或失败，都插入交易流水
        transactionDao.add(transaction);

        // 设置用户信息
        user = userDao.getEntity(user.getUserId());

        UserModel model = new UserModel();
        model.setIsOrg(true);
        model.setUserId(user.getUserId());
        model.setMobile(user.getUserMobile());
        model.setUserName(user.getUserName());

        if (profile != null) {
            model.setProfileId(profile.getProfileId());
        }

        result.setUser(model);

        return result;
    }

    @Override
    public AccountOpenResult updateOrganAccount(Long userId, OrganProfileVo organProfileVo, UserBankVo userBankVo) throws BaseException, BaseAppException {
        Preconditions.checkNotNull(userId);
        Preconditions.checkNotNull(organProfileVo);
        Preconditions.checkNotNull(organProfileVo.getProfileId());
        Preconditions.checkNotNull(userBankVo);
        Preconditions.checkNotNull(userBankVo.getUserBankId());
        //
        AccountOpenResult result = new AccountOpenResult();

        //
        User user = userDao.getEntity(userId); // 肯定是存在的


        logger.info("userId={},mobile={}", user.getUserId(), user.getUserMobile());
        logger.info("bank info={}", userBankVo);

        OrganProfile organProfile = new OrganProfile();
        org.springframework.beans.BeanUtils.copyProperties(organProfileVo, organProfile);


        //只有被拒绝的才可以再次申请开户
        OrganProfile organProfileInDB = organProfileService.qryByUserId(userId);
        if (organProfileInDB.getState().intValue() == GlobalConstant.ORGAN_STATE_NOT_PASS) {

        } else {
            logger.warn("in valid request");
            ExceptionHandler.publish(ErrorConst.COMMON_INVALID_REQUEST);
        }

        if (!EqualsUtil.equals(organProfileInDB.getProfileId(), organProfile.getProfileId())) {
            logger.warn("传递的profileId和数据库中的profileId不一致");
            ExceptionHandler.publish(ErrorConst.COMMON_INVALID_REQUEST);
        }

        // 校验验证执照号唯一性
        boolean exist = organProfileService.checkBizLicenseExist(organProfile.getBusinessLicence(),
            organProfile.getProfileId());
        if (exist) {
            ExceptionHandler.publish(ErrorConst.ORGAN_BIZ_LICENCE_EXIST);
        }

        //三证合一
        if (organProfile.getThreeInOne()) {
            organProfile.setOrganCode(organProfile.getBusinessLicence());
            organProfile.setTaxRegister(organProfile.getBusinessLicence());
        }
        if (organProfile.getBusinessLicenceLongEffective()) {
            organProfile.setBusinessLicenceExpireDate(DateUtil.getMaxDate());
        }
        if (organProfile.getInstreprIdNoLongEffective()) {
            organProfile.setInstreprIdNoExpireDate(DateUtil.getMaxDate());
        }

        UserBank bankEntity = new UserBank();
        org.springframework.beans.BeanUtils.copyProperties(userBankVo, bankEntity);


        List<UserBank> userBanks = userBankDao.getListByUserId(userId);

        UserBank userBankInDB = null;
        for (int i = 0; i < userBanks.size(); i++) {
            UserBank bank = userBanks.get(i);
            if (EqualsUtil.equals(bank.getUserBankId(), bankEntity.getUserBankId())) {
                userBankInDB = bank;
                break;
            }

        }
        if (userBankInDB == null) {
            logger.warn("传递的userBankId={}和db中不符", bankEntity.getUserBankId());
            ExceptionHandler.publish(ErrorConst.COMMON_INVALID_REQUEST);
        }


        bankEntity.setCapitalMode(GlobalConstant.CAPTIAL_MODE_K);
        bankEntity.setUserId(user.getUserId());

        // 获取恒生银行编号
        String bankHSCode = "";
        List<Lookup> lookups = lookupDao.getLookupByType(RuleConstant.RULE_LOOKUP_TYPE_HSBANK);
        for (Lookup lookup : lookups) {
            if (lookup.getComponentValue().equals(bankEntity.getBankCode())) {
                bankHSCode = lookup.getRuleValue();
                break;
            }
        }
        if (StringUtil.isEmpty(bankHSCode)) {
            result.setSuccess(false);
            result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
            result.setErrorCode(ErrorConstant.ERROR_NO_BANK_CARD_FIND);
            result.setErrorMessage(MessageUtil.getErrorMessage(ErrorConstant.ERROR_NO_BANK_CARD_FIND,
                ErrorConstant.PLACEHOLDER_FIELD_NO_FIND_FIELD, bankEntity.getBankCode()));
            return result;
        }


        // 调用开户接口
        FundAcctOpenDto dto = new FundAcctOpenDto();

        dto.setClient_name(HsUtil.getClientName(organProfile.getCompanyName()));
        dto.setClient_full_name(organProfile.getCompanyName());

        dto.setId_kind_gb(HsConst.ID_KIND_GB_BUSINESS_LICENSE);
        dto.setId_no(organProfile.getBusinessLicence());
        dto.setPassword(MD5.MD5Encode(organProfileVo.getTradePassword()));
        dto.setAddress(organProfile.getAddress());
        dto.setMobile_tel(user.getUserMobile());
        dto.setHome_tel(user.getUserMobile());

        dto.setBank_no(bankHSCode);
        dto.setBank_name(bankEntity.getBankName());
        dto.setBank_account(bankEntity.getUserBankNo());
        dto.setBank_account_name(organProfile.getCompanyName());
        dto.setBank_account_name_long(bankEntity.getBankAccountName());

//        dto.setFund_card(bankEntity.getExternalProtocolNo());
        dto.setCapital_mode(bankEntity.getCapitalMode());
        dto.setRemittance_no("01");


        dto.setCust_type(GlobalConstant.CUST_TYPE_ORGANIZATION); // 机构
        dto.setCompany_name(organProfile.getCompanyName());
        dto.setTax_register(organProfile.getTaxRegister());
        dto.setBusiness_range(organProfile.getBusinessRange());

        dto.setInstrepr_name(organProfile.getInstreprName());
        dto.setInstrepr_id_no(organProfile.getInstreprIdNo());
        dto.setInstrepr_id_enddate(DateUtil.format(organProfile.getInstreprIdNoExpireDate(), "yyyyMMdd"));
        dto.setReg_address(organProfile.getAddress());
        dto.setTrade(organProfile.getTrade());
        dto.setCor_property(organProfile.getCorProperty());
        dto.setReg_capital(organProfile.getRegCapital());
        dto.setAddress(organProfile.getAddress());
        dto.setZipcode(organProfile.getPostcode());
        dto.setHome_tel(user.getUserMobile());

        // 经办人
        dto.setContact_name(organProfile.getContactName());
        dto.setContact_tel(organProfile.getContactTel());
        dto.setContact_id_no(organProfile.getContactIdNo());

        dto.setBeneficiary(organProfile.getBeneficiary());// 实际受益人
        dto.setHolding_name(organProfile.getOwner());//实际控制人
        dto.setBranchbank(bankEntity.getBranchbank());//银行联号

        Map<String, Object> map = fundacctDirectOpenAcctService.openAcct(dto);

        if (!HsResponseUtil.isOperationOk(map)) {
            String errorInfo = map.get(HSOutputParameterNames.ERROR_INFO).toString();
            result.setSuccess(false);
            result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
            result.setErrorCode(ErrorConstant.ERROR_HUNDSUNAPI_WRONG);
            result.setErrorMessage(errorInfo);
            logger.error("open org Account errr info:{}", errorInfo);
        } else {
            // 只有成功时才有交易账号返回
            String externalTradeAccount = map.get(HSOutputParameterNames.TRADE_ACCO).toString();
            // 返回成功
            result.setSuccess(true);

            // 更新用户银行表
            bankEntity.setExternalTradeAccount(externalTradeAccount);
            bankEntity.setUserBankOwner(organProfile.getCompanyName());
            bankEntity.setUserBankMobile(user.getUserMobile());
            userBankDao.update(bankEntity);

            // 更新用户表
            user.setExternalClientId(map.get(HSOutputParameterNames.CLIENT_ID).toString());
            user.setUserName(organProfile.getCompanyName());
            userDao.updateUser(user);

            // 添加机构扩展资料
            organProfile.setUserId(user.getUserId());
            organProfile.setState(GlobalConstant.ORGAN_STATE_AUDITING);
            organProfileService.addOrUpdateByProfileId(organProfile);

            logger.info("update user profile info");
        }

        // TODO 需要考虑一种情况，即最后更新交易账号失败，但恒生开户接口已调用成功，需要回滚？
        // 插入交易记录流水
        Transaction transaction = ObjectCreator.createTransaction(map);
        // 不管成功或失败，都插入交易流水
        transactionDao.add(transaction);

        // 设置用户信息
        user = userDao.getEntity(user.getUserId());

        UserModel model = new UserModel();
        model.setIsOrg(true);
        model.setUserId(user.getUserId());
        model.setMobile(user.getUserMobile());
        model.setUserName(user.getUserName());

        result.setUser(model);

        return result;
    }

    @Override
    public AccountOpenResult updateOrganAccountNew(Long userId, OrganProfileVoNew organProfileVoNew, UserBankVo userBankVo) throws BaseException, BaseAppException {
        AccountOpenResult result = new AccountOpenResult();

        //
        User user = userDao.getEntity(userId); // 肯定是存在的

        OrganProfile organProfile = new OrganProfile();
        org.springframework.beans.BeanUtils.copyProperties(organProfileVoNew, organProfile);


        //只有被拒绝的才可以再次申请开户
        OrganProfile organProfileInDB = organProfileService.getById(organProfileVoNew.getProfileId());
        if (organProfileInDB.getState().intValue() == GlobalConstant.ORGAN_STATE_NOT_PASS) {

        } else {
            logger.warn("in valid request");
            ExceptionHandler.publish(ErrorConst.COMMON_INVALID_REQUEST);
        }

        if (!EqualsUtil.equals(organProfileInDB.getProfileId(), organProfile.getProfileId())) {
            logger.warn("传递的profileId和数据库中的profileId不一致");
            ExceptionHandler.publish(ErrorConst.COMMON_INVALID_REQUEST);
        }

        // 校验验证执照号唯一性
        boolean exist = organProfileService.checkBizLicenseExist(organProfile.getBusinessLicence(),
            organProfile.getProfileId());
        if (exist) {
            ExceptionHandler.publish(ErrorConst.ORGAN_BIZ_LICENCE_EXIST);
        }

        organProfile.setOrganCode(organProfile.getBusinessLicence());
        organProfile.setTaxRegister(organProfile.getBusinessLicence());

        organProfile.setBusinessLicenceExpireDate(DateUtil.getMaxDate());

        organProfile.setInstreprIdNoExpireDate(DateUtil.getMaxDate());


        UserBank bankEntity = new UserBank();
        org.springframework.beans.BeanUtils.copyProperties(userBankVo, bankEntity);


        List<UserBank> userBanks = userBankDao.getListByUserId(userId);

//        UserBank userBankInDB = null;
//        for (int i = 0; i < userBanks.size(); i++) {
//            UserBank bank = userBanks.get(i);
//            if (EqualsUtil.equals(bank.getUserBankId(), bankEntity.getUserBankId())) {
//                userBankInDB = bank;
//                break;
//            }
//
//        }
//        if (userBankInDB == null) {
//            logger.warn("传递的userBankId={}和db中不符", bankEntity.getUserBankId());
//            ExceptionHandler.publish(ErrorConst.COMMON_INVALID_REQUEST);
//        }


        bankEntity.setCapitalMode(GlobalConstant.CAPTIAL_MODE_K);
        bankEntity.setUserId(user.getUserId());

        // 获取恒生银行编号
        String bankHSCode = "";
        List<Lookup> lookups = lookupDao.getLookupByType(RuleConstant.RULE_LOOKUP_TYPE_HSBANK);
        for (Lookup lookup : lookups) {
            if (lookup.getComponentValue().equals(bankEntity.getBankCode())) {
                bankHSCode = lookup.getRuleValue();
                break;
            }
        }
        if (StringUtil.isEmpty(bankHSCode)) {
            result.setSuccess(false);
            result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
            result.setErrorCode(ErrorConstant.ERROR_NO_BANK_CARD_FIND);
            result.setErrorMessage(MessageUtil.getErrorMessage(ErrorConstant.ERROR_NO_BANK_CARD_FIND,
                ErrorConstant.PLACEHOLDER_FIELD_NO_FIND_FIELD, bankEntity.getBankCode()));
            return result;
        }


        // 调用开户接口
        FundAcctOpenDto dto = new FundAcctOpenDto();

        dto.setClient_name(HsUtil.getClientName(organProfile.getCompanyName()));
        dto.setClient_full_name(organProfile.getCompanyName());

        dto.setId_kind_gb(HsConst.ID_KIND_GB_BUSINESS_LICENSE);
        dto.setId_no(organProfile.getBusinessLicence());
        dto.setPassword(MD5.MD5Encode(organProfileVoNew.getTradePassword()));
        dto.setAddress(organProfile.getAddress());
        dto.setMobile_tel(user.getUserMobile());
        dto.setHome_tel(user.getUserMobile());

        dto.setBank_no(bankHSCode);
        dto.setBank_name(bankEntity.getBankBranchName());
        dto.setBank_account(bankEntity.getUserBankNo());
        dto.setBank_account_name(organProfile.getCompanyName());
        dto.setBank_account_name_long(bankEntity.getBankAccountName());

//        dto.setFund_card(bankEntity.getExternalProtocolNo());
        dto.setCapital_mode(bankEntity.getCapitalMode());
        dto.setRemittance_no("01");


        dto.setCust_type(GlobalConstant.CUST_TYPE_ORGANIZATION); // 机构
        dto.setCompany_name(organProfile.getCompanyName());
        dto.setTax_register(organProfile.getTaxRegister());
        dto.setBusiness_range(organProfile.getBusinessRange());

        dto.setInstrepr_name(organProfile.getInstreprName());
        dto.setInstrepr_id_no(organProfile.getInstreprIdNo());
        dto.setInstrepr_id_enddate(DateUtil.format(organProfile.getInstreprIdNoExpireDate(), "yyyyMMdd"));
        dto.setReg_address(organProfile.getAddress());
        dto.setTrade(organProfile.getTrade());
        dto.setCor_property(organProfile.getCorProperty());
        dto.setReg_capital(organProfile.getRegCapital());
        dto.setAddress(organProfile.getAddress());
        dto.setZipcode(organProfile.getPostcode());
        dto.setHome_tel(user.getUserMobile());

        // 经办人
        dto.setContact_name(organProfile.getContactName());
        dto.setContact_tel(organProfile.getContactTel());
        dto.setContact_id_no(organProfile.getContactIdNo());

        dto.setBeneficiary(organProfile.getBeneficiary());// 实际受益人
        dto.setHolding_name(organProfile.getOwner());//实际控制人
        dto.setBranchbank(bankEntity.getBranchbank());//银行联号

        Map<String, Object> map = fundacctDirectOpenAcctService.openAcct(dto);

        if (!HsResponseUtil.isOperationOk(map)) {
            String errorInfo = map.get(HSOutputParameterNames.ERROR_INFO).toString();
            result.setSuccess(false);
            result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
            result.setErrorCode(ErrorConstant.ERROR_HUNDSUNAPI_WRONG);
            result.setErrorMessage(errorInfo);
            logger.error("open org Account errr info:{}", errorInfo);
        } else {
            // 只有成功时才有交易账号返回
            String externalTradeAccount = map.get(HSOutputParameterNames.TRADE_ACCO).toString();
            // 返回成功
            result.setSuccess(true);

            // 更新用户银行表
            bankEntity.setExternalTradeAccount(externalTradeAccount);
            bankEntity.setUserBankOwner(organProfile.getCompanyName());
            bankEntity.setUserBankMobile(user.getUserMobile());
            userBankDao.update(bankEntity);

            // 更新用户表
            user.setExternalClientId(map.get(HSOutputParameterNames.CLIENT_ID).toString());
            user.setUserName(organProfile.getCompanyName());
            userDao.updateUser(user);

            // 添加机构扩展资料
            organProfile.setUserId(user.getUserId());
            organProfile.setState(GlobalConstant.ORGAN_STATE_AUDITING);
            organProfileService.addOrUpdateByProfileId(organProfile);

            logger.info("update user profile info");
        }

        // TODO 需要考虑一种情况，即最后更新交易账号失败，但恒生开户接口已调用成功，需要回滚？
        // 插入交易记录流水
        Transaction transaction = ObjectCreator.createTransaction(map);
        // 不管成功或失败，都插入交易流水
        transactionDao.add(transaction);

        // 设置用户信息
        user = userDao.getEntity(user.getUserId());

        UserModel model = new UserModel();
        model.setIsOrg(true);
        model.setUserId(user.getUserId());
        model.setMobile(user.getUserMobile());
        model.setUserName(user.getUserName());

        result.setUser(model);

        return result;
    }

    @Override
    public OrganInfoResult qryOrganInfo(Long userId) throws BaseAppException {

        OrganInfoResult result = new OrganInfoResult();
        result.setSuccess(false);

        OrganProfile profile = organProfileService.qryByUserId(userId);

        if (profile != null) {
            OrganProfile targetOrganProfile = new OrganProfile();

            org.springframework.beans.BeanUtils.copyProperties(profile, targetOrganProfile,
                "state", "createDate", "createUserId", "lastUpdatedDate", "lastUpdatedUserId");

            //如果是三证合一，则不需要传递
            if (targetOrganProfile.getThreeInOne()) {
                targetOrganProfile.setOrganCode(null);
                targetOrganProfile.setTaxRegister(null);
            }

            // 如果营业执照长期有效，则不传递具体内容
            if (targetOrganProfile.getBusinessLicenceLongEffective()) {
                targetOrganProfile.setBusinessLicenceExpireDate(null);
            }

            // 法人身份证长期有效，则不传递
            if (targetOrganProfile.getInstreprIdNoLongEffective()) {
                targetOrganProfile.setInstreprIdNo(null);
            }


            result.setOrganProfile(targetOrganProfile);
        }

        List<UserBank> userBanks = userBankDao.getListByUserId(userId);

        if (ListUtil.isNotEmpty(userBanks)) {
            if (userBanks.size() > 1) {
                logger.warn("organ[{}] has more 1 bank.", userId);
            }

            UserBank sourceBank = userBanks.get(0);
            UserBank targetBank = new UserBank();

            org.springframework.beans.BeanUtils.copyProperties(sourceBank, targetBank,
                "createDate", "createUserId", "lastUpdatedDate", "lastUpdatedUserId", "isValid",
                "externalTradeAccount", "externalProtocolNo", "capitalMode");


            result.setUserBank(targetBank);
        }

        result.setSuccess(true);
        return result;
    }

    @Override
    public OrganInfoResult qryOrganInfoByProfileId(Long profileId) throws BaseAppException {
//        OrganInfoResult result = new OrganInfoResult();
//        result.setSuccess(false);
//        OrganProfile profile = organProfileService.getById(profileId);
//        if (profile != null) {
//            OrganProfile targetOrganProfile = new OrganProfile();
//            org.springframework.beans.BeanUtils.copyProperties(profile, targetOrganProfile,
//                "state", "createDate", "createUserId", "lastUpdatedDate", "lastUpdatedUserId");
//
////            //如果是三证合一，则不需要传递
////            if (targetOrganProfile.getThreeInOne()) {
////                targetOrganProfile.setOrganCode(null);
////                targetOrganProfile.setTaxRegister(null);
////            }
//
//            // 如果营业执照长期有效，则不传递具体内容
////            if (targetOrganProfile.getBusinessLicenceLongEffective()) {
////                targetOrganProfile.setBusinessLicenceExpireDate(null);
////            }
//
//            // 法人身份证长期有效，则不传递
////            if (targetOrganProfile.getInstreprIdNoLongEffective()) {
////                targetOrganProfile.setInstreprIdNo(null);
////            }
//
//
//            result.setOrganProfile(targetOrganProfile);
//        }
//        List<OrganBank> organBanks = organBankDao.selectAllListByProfileId(profileId);
//        result.setOrganBanks(organBanks);
//        result.setSuccess(true);
        return null;
    }


    @Override
    public LoginResult login4Organ(Long userId, String password, String deviceId, String channelId, String ip) throws BaseException, BaseAppException {
        LoginResult result = new LoginResult();
        result.setSuccess(false);

        User user = userDao.getEntity(userId);

        if (user == null) {
            logger.warn("user[userId={}] is not exist", userId);
            ExceptionHandler.publish(ErrorConst.COMMON_INVALID_LOGINID_OR_PWD);
        }

        if (!user.getIsOrg()) {
            ExceptionHandler.publish(ErrorConst.USER_ROLE_CANNOT_LOGIN_BY_ORGAN_UI);
        }

        password = MD5.MD5Encode(password);
        if (!password.equals(user.getLoginPassword())) {
            result.setErrorType(GlobalConstant.ERROR_TYPE_BUSINESS);
            result.setErrorCode(ErrorConstant.ERROR_PASSWORD_WRONG);
            result.setErrorMessage(MessageUtil.getErrorMsg(ErrorConstant.ERROR_PASSWORD_WRONG));
            return result;
        }

        // 登录成功，则生产token
        String token = generateToken(user.getUserId(), deviceId, channelId, ip);
        result.setSuccess(true);
        result.setToken(token);

        UserModel model = new UserModel();

        model.setIsOrg(true);
        model.setMobile(user.getUserMobile());
        model.setUserName(user.getUserName());
        model.setUserCard(user.getUserCard());


        //初始化客户信息
        //organClientService.initOrganInfo(user.getUserId(), model,null);
        result.setUser(model);

        //查询警示内容
        List<WarningModel> warningModels = queryService.queryWarnings();
        result.setWarnings(warningModels);

        return result;
    }

    /**
     * 机构登录
     *
     * @param mobile
     * @param password
     * @param deviceId
     * @param channelId
     * @param ip
     * @return
     */
    @Override
    public LoginResult login4OrganNew(String mobile, String password, String deviceId, String channelId, String ip) {
        LoginResult result = new LoginResult();
        result.setSuccess(false);

        User user = userDao.getEntityByMobile(mobile.trim());

        if (user == null) {
            logger.warn("user[mobile={}] is not exist", mobile);
            ExceptionHandler.publish(ErrorConstant.ERROR_MOBILE_NOT_REG);
        }


        password = MD5.MD5Encode(password);

        if (!password.equals(user.getLoginPassword())) {
            result.setErrorType(GlobalConstant.ERROR_TYPE_BUSINESS);
            result.setErrorCode(ErrorConstant.ERROR_PASSWORD_WRONG);
            result.setErrorMessage(MessageUtil.getErrorMsg(ErrorConstant.ERROR_PASSWORD_WRONG));
            return result;
        }


        // 登录成功，则生产token
        String token = generateToken(user.getUserId(), deviceId, channelId, ip);
        result.setSuccess(true);
        result.setToken(token);

        UserModel model = new UserModel();

        model.setIsOrg(true);
        model.setMobile(user.getUserMobile());
        model.setUserName(user.getUserName());
        model.setUserCard(user.getUserCard());

        boolean isAgent = false;
        List<OrganProfile> organProfiles = organProfileService.queryListByUserId(user.getUserId());
        OrganAgent agent = organAgentDao.getEntityByMobile(user.getUserMobile());
        if (organProfiles == null || organProfiles.isEmpty()) {
            if (agent != null) {
                isAgent = true;
            }
        }
        // 是否是经办人
        model.setIsContact(isAgent);

        //初始化客户信息
        //clientService.initOrganInfo(user.getUserId(), model);
        result.setUser(model);

        //查询警示内容
        List<WarningModel> warningModels = queryService.queryWarnings();
        result.setWarnings(warningModels);

        return result;
    }

    @Override
    public LoginResult changeMobile(Long userId, String authCode, String newMobile, String authCode2) throws BaseAppException {
        User user = userDao.getEntity(userId);

        boolean isExist = checkVerifyCode(user.getUserMobile(), authCode, GlobalConstant.SMS_BIZ_CODE_VERIFY);

        if (!isExist) {
            ExceptionHandler.publish(ErrorConst.SMS_INVLIAD);
        }

        isExist = checkMobile(newMobile);
        if (isExist) {
            ExceptionHandler.publish(ErrorConst.MOBILE_HAS_EXIST);
        }

        isExist = checkVerifyCode(newMobile, authCode2, GlobalConstant.SMS_BIZ_CODE_VERIFY);

        if (!isExist) {
            ExceptionHandler.publish(ErrorConst.COMMON_SMS_NEW_MOBILE_ERROR);
        }

        //更新手机号
        User record = new User();
        record.setUserId(userId);
        record.setUserMobile(newMobile);
        record.setLastUpdatedDate(new Date());
        update(record);

        // 删除验证码
        verifyDao.deleteVerifyByMobileAndBizCode(user.getUserMobile(), GlobalConstant.SMS_BIZ_CODE_VERIFY);
        verifyDao.deleteVerifyByMobileAndBizCode(newMobile, GlobalConstant.SMS_BIZ_CODE_VERIFY);

        LoginResult result = new LoginResult();
        result.setSuccess(true);

        UserModel model = new UserModel();
        model.setMobile(newMobile);
        result.setUser(model);

        return result;
    }

    @Override
    public AccountOpenResult queryOrgState(Long userId, Long profileId) {

        UserModel userModel = new UserModel();
        userModel.setIsOrg(true);

        clientService.queryOrganState(userId, userModel, profileId);

        AccountOpenResult result = new AccountOpenResult();
        result.setSuccess(true);
        result.setUser(userModel);

        return result;
    }

    @Override
    public BaseResult resetOrgLoginPassword(String mobile, String verification_code, String new_passwd) throws BaseException {
        if (!BizUtils.validatePassword(new_passwd)) {
            return new BaseResult(false, "密码不符合规则", GlobalConstant.ERROR_TYPE_BUSINESS);
        }
        User user = userDao.getEntityByMobile(mobile);
        if (user == null) {
            logger.error("No user found according mobile:" + mobile);
            return new BaseResult(false, "用户未找到", GlobalConstant.ERROR_TYPE_BUSINESS);
        }
        boolean verify_code = checkVerifyCode(mobile, verification_code, GlobalConstant.SMS_BIZ_CODE_VERIFY);
        if (!verify_code) {
            return new BaseResult(false, "验证码验证失败", GlobalConstant.ERROR_TYPE_BUSINESS);
        }
        //删除验证码
        verifyDao.deleteVerifyByMobileAndBizCode(mobile, GlobalConstant.SMS_BIZ_CODE_VERIFY);
        logger.info("User: " + mobile + " reset login password.");
        user.setLoginPassword(MD5.MD5Encode(new_passwd));
        userDao.updateUser(user);
        return new BaseResult();
    }

    @Override
    public BaseResult resetOrgTradePwd(Long userId, Long profileId, String authCode, String newTradePwd) {
        BaseResult result = new BaseResult(false);

        if (!BizUtils.validateTradePasswd(newTradePwd)) {
            ExceptionHandler.publish(ErrorConstant.ERROR_TRADE_PWD_INVALID);
        }
        User user = userDao.getEntity(userId);

        // 只有审批通过的用户才可以修改密码
        OrganProfile organProfile = organProfileService.getById(profileId);
        if (organProfile == null) {
            logger.warn("用户还未开户");
            ExceptionHandler.publish(ErrorConstant.ERROR_NO_ACCOUNT);
        }

        if (!EqualsUtil.equals(organProfile.getState().intValue(), GlobalConstant.ORGAN_STATE_PASS)) {
            logger.warn("该机构账户开户还在审批中（或审批不通过）");
            ExceptionHandler.publish(ErrorConst.ORGAN_OPEN_ACCT_IS_NOT_SUC);
        }

        String mobile = user.getUserMobile();

        if (!checkVerifyCode(mobile, authCode, GlobalConstant.SMS_BIZ_CODE_VERIFY)) {
            ExceptionHandler.publish(ErrorConst.SMS_INVLIAD);
        }
        //删除验证码
        verifyDao.deleteVerifyByMobileAndBizCode(mobile, GlobalConstant.SMS_BIZ_CODE_VERIFY);
        List<UserBank> banks = userBankDao.getListByUserId(userId);
        if (banks.size() == 0) {
            return new BaseResult(false, "未绑定银行卡", GlobalConstant.ERROR_TYPE_BUSINESS);
        }
        UserBank first = banks.get(0);
        logger.info("User[mobile={}] begin to reset trade password.", mobile);

        Map<String, Object> res = clearTradePassword.clearTradePasswd(first.getExternalTradeAccount(),
            MD5.MD5Encode(newTradePwd));

        if (!HsResponseUtil.isOperationOk(res)) {
            logger.warn("User[mobile={}] reset trade password fail!", mobile);
            return new BaseResult(false, "调用恒生接口失败", GlobalConstant.ERROR_TYPE_APPLICATION);
        }
        logger.info("User[mobile={}] reset trade password successfully!", mobile);

        result.setSuccess(true);
        return result;
    }

    @Override
    public Boolean checkOrgAcctIsOpen(Long userId) {
        Preconditions.checkNotNull(userId, "userId cannot null");

        OrganProfile profile = organProfileService.qryByUserId(userId);

        if (profile == null) {
            logger.warn("userId[{}]还未补充资料", userId);
            return false;
        }

        if (EqualsUtil.equals(profile.getState().intValue(), GlobalConstant.ORGAN_STATE_PASS)) {
            return true;
        }

        logger.warn("userId[{}]还未审批通过", userId);
        return false;
    }
    @Override
    public Boolean checkOrgAcctStatus(Long profileId) {
        Preconditions.checkNotNull(profileId, "userId cannot null");

        OrganProfile profile = organProfileService.qryByProfileId(profileId);

        if (profile == null) {
            logger.warn("userId[{}]还未补充资料", profileId);
            return false;
        }

        if (EqualsUtil.equals(profile.getState().intValue(), GlobalConstant.ORGAN_STATE_PASS)) {
            return true;
        }

        logger.warn("userId[{}]还未审批通过", profileId);
        return false;
    }
    @Override
    public void checkOrgAcctStateAndSMS() {
        // 查询审核中的机构用户
        // 查询具体的机构状态
        // 向恒生发送请求
        // 更新最新状态
        // 发送短信

        OrganProfile record = new OrganProfile();
        record.setState(GlobalConstant.ORGAN_STATE_AUDITING);

        Pageable pageable;
        int page = 1, PAGE_SIZE = 20;


        boolean hasMoreData = true;
        while (hasMoreData) {
            pageable = new PageRequest(page++, PAGE_SIZE);

            Page<OrganProfile> orgPages = organProfileService.query(record, pageable);

            if (orgPages == null || orgPages.getTotalElements() == 0) {
                logger.info("no auditing org account....");
                hasMoreData = false;
                continue;
            }

            List<OrganProfile> orgs = orgPages.getContent();

            if (orgs.size() < PAGE_SIZE) {
                logger.info("has no more data.");
                hasMoreData = false;
            }

            for (int i = 0, j = orgs.size(); i < j; i++) {
                OrganProfile organProfile = orgs.get(i);

                User user = userDao.getEntity(organProfile.getUserId());

                //add
                String agentMobile = null;
                Long agentId = organProfile.getOrganAgentId();

                if (agentId != null) {
                    OrganAgent agent = organAgentDao.selectByPrimaryKey(agentId);

                    if (agent != null) {
                        agentMobile = agent.getOrganAgentMobile();
                    }
                }

                logger.info("userId={},clientId={},profileId={}", organProfile.getUserId(), user.getUserId(), organProfile.getProfileId());

                AccountApplyModel accountApplyModel = null;
                try {
                    accountApplyModel = queryService.queryAccountLatestApply(organProfile.getExternalClientId());
                } catch (Exception e) {
                    logger.error("fail to query org apply", e);
                    continue;
                }

                CheckFlag checkFlag = CheckFlag.get(accountApplyModel.getCheck_flag());
                logger.info("query org account [{}] in hundson", checkFlag);

                if (checkFlag == null) {
                    logger.warn("checkFlag is null, skip it.");
                    continue;
                }

                // 更新用户状态
                if (EqualsUtil.equals(accountApplyModel.getCheck_flag(), CheckFlag.NOT_PASS.getCode())
                    || EqualsUtil.equals(accountApplyModel.getCheck_flag(), CheckFlag.PASS_AND_AUDIT.getCode())
                    || EqualsUtil.equals(accountApplyModel.getCheck_flag(), CheckFlag.REJECT.getCode())) {

                    logger.info("userId={},profileId={} not pass", organProfile.getUserId(), organProfile.getProfileId());

                    organProfileService.updateState(organProfile.getProfileId(), GlobalConstant.ORGAN_STATE_NOT_PASS);
                    smsSimpleService.sendAsync(user.getUserMobile(), GlobalConstant.SMS_TPL_NOTIFY_ORG_FAIL);

                    if (agentMobile != null) {
                        smsSimpleService.sendAsync(agentMobile, GlobalConstant.SMS_TPL_NOTIFY_ORG_FAIL);
                    }

                } else if (EqualsUtil.equals(accountApplyModel.getCheck_flag(), CheckFlag.PASS.getCode())) {

                    logger.info("userId={},profileId={} has audited", organProfile.getUserId(), organProfile.getProfileId());

                    organProfileService.updateState(organProfile.getProfileId(), GlobalConstant.ORGAN_STATE_PASS);
                    smsSimpleService.sendAsync(user.getUserMobile(), GlobalConstant.SMS_TPL_NOTIFY_ORG_SUC);

                    if (agentMobile != null) {
                        smsSimpleService.sendAsync(agentMobile, GlobalConstant.SMS_TPL_NOTIFY_ORG_SUC);
                    }

                    // 审批通过，做一个最低风险等级的风险测评
                    paperInfoService.addDefaultTestResult(user.getUserId(), organProfile.getProfileId());
                }
            }
        }
    }

    @Override
    public List<User> queryList(Integer pageIndex, Integer pageSize, UserExt user) {
        return userDao.queryList(pageIndex, pageSize, user);
    }

    @Override
    public List<User> getInviteUserInfos(Integer pageIndex, Integer pageSize, Long userId) {
        return userDao.getInviteUserInfos(pageIndex, pageSize, userId);
    }


    @Override
    public Integer queryListCount(UserExt user) {
        return userDao.queryListCount(user);
    }

    @Override
    @Transactional(rollbackFor = {BaseException.class})
    public String registerAccount(User entity, UserSession sessionEntity, String ip) throws BaseException {

        Preconditions.checkNotNull(entity, "Parameter 'User' Is Null!");

        logger.info("registerAccount - mobile={}", entity.getUserMobile());

        try {

            Verify verifyEntity = new Verify();
            verifyEntity.setBizCode(GlobalConstant.SMS_BIZ_CODE_VERIFY);
            verifyEntity.setMobile(entity.getUserMobile());
            // 删除验证码
            verifyDao.deleteVerifyByMobileAndBizCode(verifyEntity);

            // 对登录密码加密
            entity.setLoginPassword(MD5.MD5Encode(entity.getLoginPassword()));
            if (StringUtil.isNotEmpty(entity.getTradePassword())) {
                entity.setTradePassword(MD5.MD5Encode(entity.getTradePassword()));
            }

            entity.setIsOrg(false);
            entity.setUserFrom(GlobalConstant.USER_FROM_APP);
            userDao.add(entity);

            // 登录获取token
            String token = generateToken(entity.getUserId(), sessionEntity.getDeviceId(), sessionEntity.getChannelId(),
                ip);

            return token;

        } catch (Exception e) {
            ExceptionUtil.logError(logger, "registerAccount - Exception:", e);
            throw new SystemDBException("registerAccount Failure!", e);
        }
    }

    // 增开交易账号
    @Override
    public AccountOpenResult addAccount(Long userId, String idNo, String tradePassword, String userName,
                                        String bankCode, String bankNo, String bankName, String mobile, String capitalMode,
                                        String externalProtocolNo, String vcBranchbank, String vcBankName) throws BaseException {

        logger.info("addAccount - userId={}, idNo={}, userName={}, bankCode={}, bankNo={}, bankName={}, mobile={}, capitalMode={}, externalProtocolNo={}",
            userId, idNo, userName, bankCode, bankNo, bankName, mobile, capitalMode, externalProtocolNo);

        AccountOpenResult result = new AccountOpenResult();
        try {

            User user = userDao.getEntity(userId);
            if (user == null || StringUtil.isEmpty(user.getExternalClientId())) {
                result.setSuccess(false);
                result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
                result.setErrorCode(ErrorConstant.ERROR_NO_ACCOUNT);
                return result;
            }

            // 根据恒生银行编号
            String bankHSCode = "";
            List<Lookup> lookups = lookupDao.getLookupByType(RuleConstant.RULE_LOOKUP_TYPE_HSBANK);
            for (Lookup lookup : lookups) {
                if (lookup.getComponentValue().equals(bankCode)) {
                    bankHSCode = lookup.getRuleValue();
                    break;
                }
            }
            if (StringUtil.isEmpty(bankHSCode)) {
                result.setSuccess(false);
                result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
                result.setErrorCode(ErrorConstant.ERROR_NO_BANK_CARD_FIND);
                result.setErrorMessage(MessageUtil.getErrorMessage(ErrorConstant.ERROR_NO_BANK_CARD_FIND,
                    ErrorConstant.PLACEHOLDER_FIELD_NO_FIND_FIELD, bankCode));
                return result;
            }

            tradePassword = MD5.MD5Encode(tradePassword);

            AccountModel accountModel = queryService.getMainAccount(user.getExternalClientId());
            if (accountModel == null || StringUtil.isEmpty(accountModel.getTradeAccount())) {
                result.setSuccess(false);
                result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
                result.setErrorCode(ErrorConstant.ERROR_NO_MAIN_ACCOUNT_FIND);
                return result;
            }
            String mainTradeAccount = accountModel.getTradeAccount();
            Map<String, Object> map = tradeAccountAddAcctService.addAcct(idNo, tradePassword, userName, bankHSCode,
                bankNo, bankName, mobile, externalProtocolNo, capitalMode, mainTradeAccount, vcBankName, vcBranchbank);

            if (!HsResponseUtil.isOperationOk(map)) {
                String errorInfo = map.get(HSOutputParameterNames.ERROR_INFO).toString();

                if (errorInfo.contains("您已经有")) {
                    errorInfo = MessageUtil.getErrorMsg(ErrorConstant.ERROR_CHANNEL_SAME_BANK_MAX_ONE);
                }

                result.setSuccess(false);
                result.setErrorCode(ErrorConstant.ERROR_HUNDSUNAPI_WRONG);
                result.setErrorMessage(errorInfo);
                logger.error("addAccount - error info:" + errorInfo);
            } else {
                // 只有成功时才有交易账号返回
                String externalTradeAccount = map.get(HSOutputParameterNames.TRADE_ACCO).toString();
                // 返回成功
                result.setSuccess(true);

                // 插入用户银行表
                UserBank bankEntity = ObjectCreator.createUserBank(bankCode, bankName, capitalMode, externalProtocolNo,
                    externalTradeAccount, mobile, bankNo, userName, userId, vcBranchbank, vcBankName);
                userBankDao.add(bankEntity);
            }

            // TODO 需要考虑一种情况，即最后更新交易账号失败，但恒生开户接口已调用成功，需要回滚？
            // 插入交易记录流水
            Transaction transaction = ObjectCreator.createTransaction(map);
            // 不管成功或失败，都插入交易流水
            transactionDao.add(transaction);

            return result;
        } catch (BaseException baseException) {
            throw baseException;
        } catch (Exception e) {
            ExceptionUtil.logError(logger, "addAccount - Exception:", e);
            throw new SystemDBException("addAccount Failure!", e);
        }
    }

    @Override
    @Transactional(rollbackFor = {BaseException.class})
    public AccountOpenResult openAccount(User entity, UserBank bankEntity) throws BaseException {
        if (entity == null) {
            throw new InterfaceFieldNoFindExcepiton("Parameter 'User' Is Null!");
        }

        logger.info("openAccount User ID:" + entity.getUserId());

        AccountOpenResult result = new AccountOpenResult();
        try {

            // 获取恒生银行编号
            String bankHSCode = "";
            List<Lookup> lookups = lookupDao.getLookupByType(RuleConstant.RULE_LOOKUP_TYPE_HSBANK);
            for (Lookup lookup : lookups) {
                if (lookup.getComponentValue().equals(bankEntity.getBankCode())) {
                    bankHSCode = lookup.getRuleValue();
                    break;
                }
            }
            if (StringUtil.isEmpty(bankHSCode)) {
                result.setSuccess(false);
                result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
                result.setErrorCode(ErrorConstant.ERROR_NO_BANK_CARD_FIND);
                result.setErrorMessage(MessageUtil.getErrorMessage(ErrorConstant.ERROR_NO_BANK_CARD_FIND,
                    ErrorConstant.PLACEHOLDER_FIELD_NO_FIND_FIELD, bankEntity.getBankCode()));
                return result;
            }

            // 对交易密码加密
            // 不保存交易密码到本地数据库
            // entity.setTradePassword(MD5.MD5Encode(entity.getTradePassword()));
            String tradePassword = MD5.MD5Encode(entity.getTradePassword());
            entity.setTradePassword("");

            // 调用交易接口
            Map<String, Object> map = fundacctDirectOpenAcctService.openAcct(entity.getUserCard(), tradePassword,
                entity.getUserName(), bankHSCode, bankEntity.getUserBankNo(), bankEntity.getBankName(),
                bankEntity.getUserBankMobile(), bankEntity.getExternalProtocolNo(), bankEntity.getCapitalMode());

            if (!HsResponseUtil.isOperationOk(map)) {
                String errorInfo = map.get(HSOutputParameterNames.ERROR_INFO).toString();
                result.setSuccess(false);
                result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
                result.setErrorCode(ErrorConstant.ERROR_HUNDSUNAPI_WRONG);
                result.setErrorMessage(errorInfo);
                logger.error("openAccount - error info:" + errorInfo);
            } else {
                // 只有成功时才有交易账号返回
                String externalTradeAccount = map.get(HSOutputParameterNames.TRADE_ACCO).toString();
                // 返回成功
                result.setSuccess(true);

                // 插入用户银行表
                bankEntity.setExternalTradeAccount(externalTradeAccount);
                userBankDao.add(bankEntity);
                // 更新用户表
                entity.setExternalClientId(map.get(HSOutputParameterNames.CLIENT_ID).toString());
                userDao.updateUser(entity);
            }

            // TODO 需要考虑一种情况，即最后更新交易账号失败，但恒生开户接口已调用成功，需要回滚？
            // 插入交易记录流水
            Transaction transaction = ObjectCreator.createTransaction(map);
            // 不管成功或失败，都插入交易流水
            transactionDao.add(transaction);

            // 设置用户信息
            entity = userDao.getEntity(entity.getUserId());
            UserModel model = new UserModel();
            model.setMobile(entity.getUserMobile());
            model.setUserName(entity.getUserName());
            result.setUser(model);

            return result;
        } catch (BaseException baseException) {
            throw baseException;
        } catch (Exception e) {
            ExceptionUtil.logError(logger, "openAccount - Exception:", e);
            throw new SystemDBException("openAccount Failure!", e);
        }
    }

    @Override
    @Transactional(rollbackFor = {BaseException.class})
    public AccountOpenResult openAccountNew(User entity, UserProfileVo userProfileVo, UserBank bankEntity) throws BaseException {
        Assert.notNull(entity);
        Assert.notNull(userProfileVo);
        Assert.notNull(bankEntity);

        logger.info("openAccount User ID:{}", entity.getUserId());

        AccountOpenResult result = new AccountOpenResult();
        try {

            // 获取恒生银行编号
            String bankHSCode = "";
            List<Lookup> lookups = lookupDao.getLookupByType(RuleConstant.RULE_LOOKUP_TYPE_HSBANK);
            for (Lookup lookup : lookups) {
                if (lookup.getComponentValue().equals(bankEntity.getBankCode())) {
                    bankHSCode = lookup.getRuleValue();
                    break;
                }
            }
            if (StringUtil.isEmpty(bankHSCode)) {
                result.setSuccess(false);
                result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
                result.setErrorCode(ErrorConstant.ERROR_NO_BANK_CARD_FIND);
                result.setErrorMessage(MessageUtil.getErrorMessage(ErrorConstant.ERROR_NO_BANK_CARD_FIND,
                    ErrorConstant.PLACEHOLDER_FIELD_NO_FIND_FIELD, bankEntity.getBankCode()));
                return result;
            }

            // 对交易密码加密
            // 不保存交易密码到本地数据库
            // entity.setTradePassword(MD5.MD5Encode(entity.getTradePassword()));
            String tradePassword = MD5.MD5Encode(entity.getTradePassword());
            entity.setTradePassword("");

            // 调用开户接口
            FundAcctOpenDto dto = new FundAcctOpenDto();

            dto.setClient_name(entity.getUserName());
            dto.setId_no(entity.getUserCard());
            dto.setPassword(tradePassword);
            dto.setAddress(userProfileVo.getUserAddress());
            dto.setMobile_tel(bankEntity.getUserBankMobile());
            dto.setBank_no(bankHSCode);
            dto.setBank_name(bankEntity.getBankBranchName());
            if (bankEntity.getBranchbank() != null) {
                dto.setBranchbank(bankEntity.getBranchbank());
            }
            dto.setBank_account(bankEntity.getUserBankNo());
            dto.setBank_account_name(entity.getUserName());

            dto.setFund_card(bankEntity.getExternalProtocolNo());
            dto.setCapital_mode(bankEntity.getCapitalMode());

            dto.setBeneficiary(userProfileVo.getBeneficiary());// 实际受益人
            dto.setHolding_name(userProfileVo.getOwner());//实际控制人

            Map<String, Object> map = fundacctDirectOpenAcctService.openAcct(dto);

            if (!HsResponseUtil.isOperationOk(map)) {
                String errorInfo = map.get(HSOutputParameterNames.ERROR_INFO).toString();
                result.setSuccess(false);
                result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
                result.setErrorCode(ErrorConstant.ERROR_HUNDSUNAPI_WRONG);
                result.setErrorMessage(errorInfo);
                logger.error("openAccount - error info:" + errorInfo);
            } else {
                // 只有成功时才有交易账号返回
                String externalTradeAccount = map.get(HSOutputParameterNames.TRADE_ACCO).toString();
                // 返回成功
                result.setSuccess(true);

                // 插入用户银行表
                bankEntity.setExternalTradeAccount(externalTradeAccount);
                logger.info("开户v3 内层 联行号：{}，支行名称：{}", bankEntity.getBranchbank(), bankEntity.getBankBranchName());
                userBankDao.add(bankEntity);
                // 更新用户表
                entity.setExternalClientId(map.get(HSOutputParameterNames.CLIENT_ID).toString());
                userDao.updateUser(entity);

                // 添加扩展资料
                UserProfile userProfile = new UserProfile();
                org.springframework.beans.BeanUtils.copyProperties(userProfileVo, userProfile);
                userProfile.setUserId(entity.getUserId());

                userProfileService.addOrUpdate(userProfile);
                logger.info("add user profile info");
            }

            // TODO 需要考虑一种情况，即最后更新交易账号失败，但恒生开户接口已调用成功，需要回滚？
            // 插入交易记录流水
            Transaction transaction = ObjectCreator.createTransaction(map);
            // 不管成功或失败，都插入交易流水
            transactionDao.add(transaction);

            // 设置用户信息
            entity = userDao.getEntity(entity.getUserId());
            UserModel model = new UserModel();
            model.setMobile(entity.getUserMobile());
            model.setUserName(entity.getUserName());
            result.setUser(model);

            return result;
        } catch (BaseException baseException) {
            throw baseException;
        } catch (Exception e) {
            ExceptionUtil.logError(logger, "openAccount - Exception:", e);
            throw new SystemDBException("openAccount Failure!", e);
        }
    }


    @Override
    @Transactional(rollbackFor = {BaseException.class})
    public PaySignResult paySign_Step_One(User entity, UserBank bankEntity) throws BaseException {
        if (entity == null) {
            throw new InterfaceFieldNoFindExcepiton("Parameter 'User' Is Null!");
        }

        logger.info("paySign_Step_One User Id:" + entity.getUserId());

        PaySignResult result = new PaySignResult();
        try {

            // 获取恒生银行编号
            String bankHSCode = "";
            List<Lookup> lookups = lookupDao.getLookupByType(RuleConstant.RULE_LOOKUP_TYPE_HSBANK);
            for (Lookup lookup : lookups) {
                if (lookup.getComponentValue().equals(bankEntity.getBankCode())) {
                    bankHSCode = lookup.getRuleValue();
                    break;
                }
            }
            if (StringUtil.isEmpty(bankHSCode)) {
                result.setSuccess(false);
                result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
                result.setErrorCode(ErrorConstant.ERROR_NO_BANK_CARD_FIND);
                result.setErrorMessage(MessageUtil.getErrorMessage(ErrorConstant.ERROR_NO_BANK_CARD_FIND,
                    ErrorConstant.PLACEHOLDER_FIELD_NO_FIND_FIELD, bankEntity.getBankCode()));
                return result;
            }

            // 插入交易记录获取流水号
            Transaction transaction = new Transaction();
            transactionDao.add(transaction);
            Long transactionId = transaction.getTransactionId();
            // 设置流水号
            String serialNo = String.valueOf(transactionId);

            Map<String, Object> map = paySignContractSmsService.paySign_Step_One(serialNo, entity.getUserCard(),
                entity.getUserName(), bankHSCode, bankEntity.getUserBankNo(), bankEntity.getUserBankMobile());

            if (map.containsKey(HSOutputParameterNames.ERROR_CODE)) {
                String errorInfo = map.get(HSOutputParameterNames.ERROR_INFO).toString();
                result.setSuccess(false);
                result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
                result.setErrorCode(ErrorConstant.ERROR_HUNDSUNAPI_WRONG);
                result.setErrorMessage(errorInfo);

            } else {
                String smsSerialNo = "";
                result.setSuccess(true);
                if (map.get(HSOutputParameterNames.SMS_SERIAL_NO) != null) {
                    smsSerialNo = map.get(HSOutputParameterNames.SMS_SERIAL_NO).toString();
                }
                result.setSMSSerialNo(smsSerialNo);
                result.setOriginalSerialNo(serialNo);
            }

            transaction = ObjectCreator.createTransaction(map);
            transaction.setTransactionId(transactionId);
            // 更新数据
            transactionDao.updateTransaction(transaction);

            return result;
        } catch (BaseException baseException) {
            throw baseException;
        } catch (Exception e) {
            ExceptionUtil.logError(logger, "paySign_Step_One - Exception:", e);
            throw new SystemDBException("paySign_Step_One Failure!", e);
        }
    }

    @Override
    @Transactional(rollbackFor = {BaseException.class})
    public PaySignResult paySign_Step_Two(User entity, UserBank bankEntity, String originalSerialNo, String smsSerialNo,
                                          String mobileCode) throws BaseException {
        if (entity == null) {
            throw new InterfaceFieldNoFindExcepiton("Parameter 'User' Is Null!");
        }

        logger.info("paySign_Step_Two User Id:" + entity.getUserId());

        PaySignResult result = new PaySignResult();
        try {

            // 获取恒生银行编号
            String bankHSCode = "";
            List<Lookup> lookups = lookupDao.getLookupByType(RuleConstant.RULE_LOOKUP_TYPE_HSBANK);
            for (Lookup lookup : lookups) {
                if (lookup.getComponentValue().equals(bankEntity.getBankCode())) {
                    bankHSCode = lookup.getRuleValue();
                    break;
                }
            }
            if (StringUtil.isEmpty(bankHSCode)) {
                result.setSuccess(false);
                result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
                result.setErrorCode(ErrorConstant.ERROR_NO_BANK_CARD_FIND);
                result.setErrorMessage(MessageUtil.getErrorMessage(ErrorConstant.ERROR_NO_BANK_CARD_FIND,
                    ErrorConstant.PLACEHOLDER_FIELD_NO_FIND_FIELD, bankEntity.getBankCode()));
                return result;
            }

            // 插入交易记录获取流水号
            Transaction transaction = new Transaction();
            transactionDao.add(transaction);
            Long transactionId = transaction.getTransactionId();

            // 设置流水号
            String serialNo = String.valueOf(transactionId);
            Map<String, Object> map = paySignContractSmsService.paySign_Step_Two(serialNo, originalSerialNo,
                entity.getUserCard(), entity.getUserName(), bankHSCode, bankEntity.getUserBankNo(),
                bankEntity.getUserBankMobile(), mobileCode, smsSerialNo);

            if (map.containsKey(HSOutputParameterNames.ERROR_CODE)) {
                String errorInfo = map.get(HSOutputParameterNames.ERROR_INFO).toString();
                result.setSuccess(false);
                result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
                result.setErrorCode(ErrorConstant.ERROR_HUNDSUNAPI_WRONG);
                result.setErrorMessage(errorInfo);
            } else {
                //String protocolNo = map.get(HSOutputParameterNames.PROTOCOL_NO).toString();
                String protocolNo = "";
                if (map.get(HSOutputParameterNames.PROTOCOL_NO) != null) {
                    protocolNo = map.get(HSOutputParameterNames.PROTOCOL_NO).toString();
                }
                result.setSuccess(true);
                result.setProtocolNo(protocolNo);
            }

            // 生成对象
            transaction = ObjectCreator.createTransaction(map);
            transaction.setTransactionId(transactionId);
            // 更新数据
            transactionDao.updateTransaction(transaction);

            return result;
        } catch (BaseException baseException) {
            throw baseException;
        } catch (Exception e) {
            ExceptionUtil.logError(logger, "paySign_Step_Two - Exception:", e);
            throw new SystemDBException("paySign_Step_Two Failure!", e);
        }
    }

    @Override
    public User getUser(Long userId) throws BaseException {
        logger.info("Get User entity - User Id:" + userId);

        try {

            return userDao.getEntity(userId);

        } catch (Exception exception) {
            ExceptionUtil.logError(logger, "getUser - Exception:", exception);
            throw new SystemDBException("getUser Failure!", exception);
        }
    }

    @Override
    public User getUser(String mobile) throws BaseException {
        logger.info("Get User entity - Mobile Id:" + mobile);

        try {

            return userDao.getEntityByMobile(mobile);

        } catch (Exception exception) {
            ExceptionUtil.logError(logger, "getUser - Exception:", exception);
            throw new SystemDBException("getUser Failure!", exception);
        }
    }


    @Override
    public User getUserByToken(String token) throws BaseException {
        logger.info("Get User entity - token:" + token);

        try {

            return userDao.getEntityByToken(token);

        } catch (Exception exception) {
            ExceptionUtil.logError(logger, "getUser - Exception:", exception);
            throw new SystemDBException("getUser Failure!", exception);
        }
    }

    @Override
    @Transactional(rollbackFor = {BaseException.class})
    public void update(User entity) throws BaseException {
        if (entity == null || entity.getUserId() <= 0) {
            throw new InterfaceFieldNoFindExcepiton("Parameter 'User' Is Null!");
        }

        logger.info("Update User entity - User Id:" + entity.getUserId());

        try {

            userDao.update(entity);

        } catch (Exception e) {
            ExceptionUtil.logError(logger, "Update User entity - Exception:", e);
            throw new SystemDBException("Update User entity Failure!", e);
        }
    }

    @Override
    @Transactional(readOnly = true)
    public Boolean checkMobile(String mobile) throws BaseException {
        if (StringUtil.isEmpty(mobile)) {
            throw new InterfaceFieldNoFindExcepiton("Parameter 'mobile' Is Null!");
        }

        logger.info("checkMobile - Mobile:" + mobile);

        try {

            return userDao.isExistMobile(mobile);

        } catch (Exception e) {
            ExceptionUtil.logError(logger, "checkMobile - Exception:", e);
            throw new SystemDBException("checkMobile Failure!", e);
        }
    }

    @Override
    @Transactional(readOnly = true)
    public Boolean checkVerifyCode(String mobile, String authCode, String bizCode) throws BaseException {
        if (StringUtil.isEmpty(mobile)) {
            throw new InterfaceFieldNoFindExcepiton("Parameter 'mobile' Is Null!");
        }

        logger.info("checkVerifyCode - Mobile:" + mobile);

        try {

            Verify queryEntity = new Verify();
            queryEntity.setMobile(mobile);
            queryEntity.setBizCode(bizCode);
            Verify entity = verifyDao.getEntityByMobileAndBizCode(queryEntity);
            if (entity == null) {
                return false;
            } else {
                if (entity.getExpireDate().before(new Date())) {
                    return false;
                }

                if (!entity.getVerifyCode().equals(authCode)) {
                    return false;
                }
            }

            return true;

        } catch (Exception e) {
            ExceptionUtil.logError(logger, "checkVerifyCode - Exception:", e);
            throw new SystemDBException("checkVerifyCode Failure!", e);
        }
    }
    @Override
    public BaseResult h5Login(String loginName, String password) throws BaseException {
        BaseResult result = new BaseResult();
        User entity = userDao.getEntityByMobile(loginName);
        if(entity == null || entity.getUserId() <=0){
            result.setSuccess(false);
            result.setErrorType(GlobalConstant.ERROR_TYPE_BUSINESS);
            result.setErrorMessage("未查询到用户");
            return result;
        }
        password = MD5.MD5Encode(password);
        if (!password.equals(entity.getLoginPassword())) {
            result.setSuccess(false);
            result.setErrorType(GlobalConstant.ERROR_TYPE_BUSINESS);
            result.setErrorMessage("密码错误");
            return result;
        }
        result.setSuccess(true);
        result.setResult(entity);
        return result;
    }
    @Override
    @Transactional(rollbackFor = {BaseException.class})
    public LoginResult login(String loginName, String password, String deviceId, String channelId, String ip)
        throws BaseException {

        if (StringUtil.isEmpty(loginName)) {
            throw new InterfaceFieldNoFindExcepiton("Parameter 'loginName' Is Null!");
        }

        logger.info("login - loginName:" + loginName);

        try {

            LoginResult result = new LoginResult();
            User entity = null;
            // 手机登录
            if (loginName.length() <= GlobalConstant.MOBILE_LENGTH) {
                entity = userDao.getEntityByMobile(loginName);
            } else {// 身份证登录
                entity = userDao.getEntityByIDCard(loginName);
            }

            if (entity == null) {
                result.setSuccess(false);
                result.setErrorType(GlobalConstant.ERROR_TYPE_BUSINESS);
                result.setErrorCode(ErrorConstant.ERROR_MOBILE_NOT_REG);
                return result;
            }

//            if (entity.getIsOrg()) {
//                result.setSuccess(false);
//                result.setErrorCode(ErrorConstant.ERROR_ORG_CAN_NOT_LOGIN_BY_USER_LOGIN_UI);
//                return result;
//            }


            password = MD5.MD5Encode(password);
            if (!password.equals(entity.getLoginPassword())) {
                result.setSuccess(false);
                result.setErrorType(GlobalConstant.ERROR_TYPE_BUSINESS);
                result.setErrorCode(ErrorConstant.ERROR_PASSWORD_WRONG);
                return result;
            }

            // 登录成功，则生产token
            String token = generateToken(entity.getUserId(), deviceId, channelId, ip);
            result.setSuccess(true);
            result.setToken(token);
            UserModel model = new UserModel();
            model.setMobile(entity.getUserMobile());
            model.setUserName(entity.getUserName());
            model.setUserCard(entity.getUserCard());
            model.setIsOrg(false);
            //初始化客户信息
            clientService.initClientInfo(entity.getUserId(), model);

            model.setUserId(entity.getUserId());
            result.setUser(model);

            //查询警示内容
            List<WarningModel> warningModels = queryService.queryWarnings();
            result.setWarnings(warningModels);

            return result;
        } catch (Exception exception) {
            ExceptionUtil.logError(logger, "Login - Exception:", exception);
            throw new SystemDBException("Login Failure!", exception);
        }
    }

    @Override
    @Transactional(rollbackFor = BaseException.class)
    public String generateToken(Long userId, String deviceId, String channelId, String ip) throws BaseException {
        // 创建用户登录token信息
        Date loginTime = new Date();
        Date expireTime = DateUtils.addDay(loginTime, GlobalConstant.EXPIRED_DAYS);
        String token = UUID.randomUUID().toString().replace("-", "_");

        UserSession session = new UserSession();
        session.setUserId(userId);
        session.setChannelId(channelId);
        session.setDeviceId(deviceId);
        session.setLoginTime(loginTime);
        session.setExpireTime(expireTime);
        session.setToken(token);
        session.setIp(ip);
        // 删除之前先备份，插入历史表
        UserSession backupEntity = userSessionDao.getEntityByUserId(userId);
        if (backupEntity != null) {
            userSessionHistoryDao.addHistory(backupEntity);
            // 先删除之前的 Session
            userSessionDao.deleteByUserId(userId);
        }

        // 插入Session
        userSessionDao.add(session);

        return token;
    }

    @Override
    public Boolean checkIDCard(String idCard) throws BaseException {
        if (StringUtil.isEmpty(idCard)) {
            throw new InterfaceFieldNoFindExcepiton("Parameter 'idCard' Is Null!");
        }

        logger.info("checkIDCard - IDCard:" + idCard);

        try {

            return userDao.isExistCard(idCard);

        } catch (Exception e) {
            ExceptionUtil.logError(logger, "checkIDCard - Exception:", e);
            throw new SystemDBException("checkIDCard Failure!", e);
        }
    }

    @Override
    public Boolean checkBankNo(String bankNo, String capitalMode) throws BaseException {
        if (StringUtil.isEmpty(bankNo)) {
            throw new InterfaceFieldNoFindExcepiton("Parameter 'bankNo' Is Null!");
        }

        logger.info("checkBankNo - bankNo:" + bankNo);

        try {

            return userBankDao.isExistBankNo(bankNo, capitalMode);

        } catch (Exception e) {
            ExceptionUtil.logError(logger, "checkBankNo - Exception:", e);
            throw new SystemDBException("checkBankNo Failure!", e);
        }
    }

    @Override
    @Transactional
    public ValidateTokenResult validateToken(String token, String deviceId) throws BaseException {
        return validateToken(token, null, deviceId, false);
    }

    @Override
    @Transactional
    public ValidateTokenResult validateToken(String token, String ip, String deviceId, boolean generateNewToken)
        throws BaseException {
        if (StringUtil.isEmpty(token)) {
            throw new InterfaceFieldNoFindExcepiton("Parameter 'token' Is Null!");
        }

        logger.info("validateToken - token:" + token);

        ValidateTokenResult result = new ValidateTokenResult();
        try {

            // 用户未登录
            if (StringUtil.isEmpty(token)) {
                result.setErrorType(GlobalConstant.ERROR_TYPE_BUSINESS);
                result.setErrorCode(ErrorConstant.ERROR_NOT_LOGIN);
                result.setSuccess(false);
                return result;
            }

            // 获取用户session
            UserSession entity = userSessionDao.getEntityByToken(token);
            // 用户已在其他地方登录
            if (entity == null) {
                result.setErrorType(GlobalConstant.ERROR_TYPE_BUSINESS);
                result.setErrorCode(ErrorConstant.ERROR_LOGIN_IN_OTHER_PLACE);
                result.setSuccess(false);
                return result;
                // 该设备不是生成token的设备
            } else if (!entity.getDeviceId().equals(deviceId)) {
                result.setErrorType(GlobalConstant.ERROR_TYPE_BUSINESS);
                result.setErrorCode(ErrorConstant.ERROR_DEVICE_INVALID);
                result.setSuccess(false);
                return result;
            } else {
                // token已过期
                Date expireDate = entity.getExpireTime();
                if (expireDate.before(new Date())) {
                    result.setErrorType(GlobalConstant.ERROR_TYPE_BUSINESS);
                    result.setErrorCode(ErrorConstant.ERROR_LOGIN_EXPIRED);
                    result.setSuccess(false);
                    return result;
                } else {
                    // 每次生成新的token时过期时间延后，每次调用方法前的验证token不再更新过期时间
                    String newToken = "";
                    if (generateNewToken) {
//                        newToken = generateToken(entity.getUserId(), deviceId, entity.getChannelId(), ip);
                        Date loginTime = new Date();
                        entity.setLoginTime(loginTime);
                        Date expireTime = DateUtils.addDay(loginTime, GlobalConstant.EXPIRED_DAYS);
                        entity.setExpireTime(expireTime);
                        // 删除之前先备份，插入历史表
                        UserSession backupEntity = userSessionDao.getEntityByUserId(entity.getUserId());
                        if (backupEntity != null) {
                            userSessionHistoryDao.addHistory(backupEntity);
                            // 先删除之前的 Session
                            userSessionDao.deleteByUserId(entity.getUserId());
                        }
                        // 插入Session
                        userSessionDao.add(entity);
                        newToken = entity.getToken();

                    } else {
                        // 之前的token
                        newToken = entity.getToken();
                    }

                    result.setSuccess(true);
                    result.setUserId(entity.getUserId());
                    result.setChannelId(entity.getChannelId());
                    result.setToken(newToken);

                    return result;
                }
            }

        } catch (Exception e) {
            ExceptionUtil.logError(logger, "validateToken - Exception:", e);
            throw new SystemDBException("validateToken Failure!", e);
        }
    }

    @Override
    @Transactional(readOnly = true)
    public CardBinResult validateCardInfo(String cardNo) throws BaseException {
        CardBinResult result = null;
        if (StringUtil.isEmpty(cardNo) || cardNo.length() < 6) {
            result = new CardBinResult();
            result.setSuccess(false);
            result.setErrorType(GlobalConstant.ERROR_TYPE_BUSINESS);
            result.setErrorCode(ErrorConstant.ERROR_FIELD_NO_FIND);
        }

        logger.info("validateCardInfo - cardNo:" + cardNo);
        try {

            result = new CardBinResult();
            String bin = cardNo.substring(0, 6);
            CardBin entity = cardBinDao.getByBinLike(bin);

            // 此方法不能识别类似103的卡bin
            //CardBin entity = cardBinDao.getByBin(bin);

            /*// 因为前端代码目前还没有升级，先注释掉，继续使用以前的处理逻辑
            // 目前卡bin用前6位来判断，需要加上银行卡长度，最终才能定位一张银行卡, 卡bin的长度从9位到3位
            CardBin entity = cardBinDao.getByCardNo(cardNo);*/

            // 过滤掉被排除的银行
            List<Lookup> excludeLookups = lookupDao.getLookupByType(RuleConstant.RULE_LOOKUP_TYPE_EXCLUDE_BANK);
            // 易宝支持的银行卡
            List<Lookup> epayLookups = lookupDao.getLookupByType(RuleConstant.RULE_LOOKUP_TYPE_EPAYBANK);

            if (entity != null) {
                result.setSuccess(true);
                result.setBankCode(entity.getBankCode());
                result.setBankName(entity.getBankName());
                result.setCardType(entity.getCardType());
                // 不是支持的银行卡
                // 过滤掉被排除的银行
                boolean exclude = false;
                for (Lookup lookup : excludeLookups) {
                    if (lookup.getRuleValue().equals(result.getBankCode())) {
                        exclude = true;
                    }
                }

                // 是否在易宝支持的银行卡列表里面
                boolean include = false;
                for (Lookup lookup : epayLookups) {
                    if (lookup.getRuleValue().equals(result.getBankCode())) {
                        include = true;
                    }
                }

                if (exclude || !include) {
                    result.setValidCard(GlobalConstant.BANK_CARD_TYPE_NOT_SUPPORT);
                } else {
                    // 储蓄卡
                    if (result.getCardType().equals(GlobalConstant.CARD_TYPE_DC)) {
                        result.setValidCard(GlobalConstant.BANK_CARD_TYPE_DC);
                    } else if (result.getCardType().equals(GlobalConstant.CARD_TYPE_CC)) {
                        // 信用卡
                        result.setValidCard(GlobalConstant.BANK_CARD_TYPE_CC);
                    } else {
                        // 查不出来的默认是合法的银行卡
                        result.setValidCard(GlobalConstant.BANK_CARD_TYPE_UNDEFINE);
                    }
                }

            } else {
                // 如果没找到卡bin, 就默认为合法的银行卡
                result.setSuccess(true);
                result.setValidCard(GlobalConstant.BANK_CARD_TYPE_UNDEFINE);
            }

            return result;
        } catch (Exception exception) {
            ExceptionUtil.logError(logger, "validateCardInfo - Exception:", exception);
            throw new SystemDBException("validateCardInfo Failure!", exception);
        }
    }

    @Override
    public BaseResult update_password(Long user_id, String old_password, String new_password) {
        if (!BizUtils.validatePassword(new_password)) {
            return new BaseResult(false, "密码不符合规则");
        }
        User user = userDao.getEntity(user_id);
        String md5_password = MD5.MD5Encode(old_password);
        if (md5_password.equals(user.getLoginPassword())) {
            user.setLoginPassword(MD5.MD5Encode(new_password));
            userDao.updateUser(user);
            logger.info("Update user login password, user_id : " + user_id);
            return new BaseResult();
        } else {
            logger.info("Update user password fail because password mismatch !");
            return new BaseResult(false, "密码不匹配", GlobalConstant.ERROR_TYPE_BUSINESS);
        }
    }

    @Override
    public BaseResult resetLoginPassword(String mobile, String verification_code, String new_passwd)
        throws BaseException {
        if (!BizUtils.validatePassword(new_passwd)) {
            return new BaseResult(false, "密码不符合规则", GlobalConstant.ERROR_TYPE_BUSINESS);
        }
        User user = userDao.getEntityByMobile(mobile);
        if (user == null) {
            logger.error("No user found according mobile:" + mobile);
            return new BaseResult(false, "用户未找到", GlobalConstant.ERROR_TYPE_BUSINESS);
        }
        boolean verify_code = checkVerifyCode(mobile, verification_code, GlobalConstant.SMS_BIZ_CODE_VERIFY);
        if (!verify_code) {
            return new BaseResult(false, "验证码验证失败", GlobalConstant.ERROR_TYPE_BUSINESS);
        }
        if (user.getIsOrg()) {
            return new BaseResult(false, "机构用户找回密码请从企业用户界面进行修改", GlobalConstant.ERROR_TYPE_BUSINESS);
        }

        //删除验证码
        verifyDao.deleteVerifyByMobileAndBizCode(mobile, GlobalConstant.SMS_BIZ_CODE_VERIFY);
        logger.info("User: " + mobile + " reset login password.");
        user.setLoginPassword(MD5.MD5Encode(new_passwd));
        userDao.updateUser(user);
        return new BaseResult();
    }

    @Override
    public BaseResult resetTradePassword(Long userId, String id_card, String mobile, String verification_code,
                                         String new_passwd) throws BaseException {
        if (!BizUtils.validateTradePasswd(new_passwd)) {
            return new BaseResult(false, "密码不符合规则", GlobalConstant.ERROR_TYPE_BUSINESS);
        }
        User user = userDao.getEntity(userId);
        if (!User.USER_STATE_BANK.equals(user.getUserState())) {
            return new BaseResult(false, "用户未开户", GlobalConstant.ERROR_TYPE_BUSINESS);
        }
        if (!StringUtils.equals(user.getUserCard(), id_card)) {
            return new BaseResult(false, "身份证号码错误", GlobalConstant.ERROR_TYPE_BUSINESS);
        }
        if (!StringUtils.equals(user.getUserMobile(), mobile)) {
            return new BaseResult(false, "电话号码错误", GlobalConstant.ERROR_TYPE_BUSINESS);
        }
        if (!checkVerifyCode(mobile, verification_code, GlobalConstant.SMS_BIZ_CODE_VERIFY)) {
            return new BaseResult(false, "验证码验证失败", GlobalConstant.ERROR_TYPE_BUSINESS);
        }
        //删除验证码
        verifyDao.deleteVerifyByMobileAndBizCode(mobile, GlobalConstant.SMS_BIZ_CODE_VERIFY);
        List<UserBank> banks = userBankDao.getListByUserId(userId);
        if (banks.size() == 0) {
            return new BaseResult(false, "未绑定银行卡", GlobalConstant.ERROR_TYPE_BUSINESS);
        }
        UserBank first = banks.get(0);
        logger.info("User: " + mobile + " reset trade password.");
        Map<String, Object> res = clearTradePassword.clearTradePasswd(first.getExternalTradeAccount(),
            MD5.MD5Encode(new_passwd));
        if (!HsResponseUtil.isOperationOk(res)) {
            logger.info("User: " + mobile + " reset trade password fail!");
            return new BaseResult(false, "调用恒生接口失败", GlobalConstant.ERROR_TYPE_APPLICATION);
        }
        logger.info("User: " + mobile + " reset trade password successfully!");
        return new BaseResult();
    }

    @Override
    public BaseResult verifyVerificationCode(String mobile, String code, String bizCode) {
        if (StringUtil.isEmpty(mobile) || StringUtil.isEmpty(bizCode)) {
            throw new BaseException(ErrorConstant.ERROR_INVALID_REQUEST, null);
        }
        logger.info("checkVerifyCode - Mobile:" + mobile);
        Verify queryEntity = new Verify();
        queryEntity.setMobile(mobile);
        queryEntity.setBizCode(bizCode);
        Verify entity = verifyDao.getEntityByMobileAndBizCode(queryEntity);
        if (entity == null) {
            return new BaseResult(false, "手机号码错误");
        } else {
            if (!entity.getVerifyCode().equals(code)) {
                return new BaseResult(false, "验证码错误");
            }
            if (entity.getExpireDate().before(new Date())) {
                return new BaseResult(false, "验证码已过期");
            }
        }
        return new BaseResult();
    }

    @Override
    public BaseResult verifyUserIdAndMobile(String id_card, String mobile, String verification_code) {
        if (StringUtil.isEmpty(id_card) || StringUtil.isEmpty(mobile) || StringUtil.isEmpty(verification_code)) {
            throw new BaseException(ErrorConstant.ERROR_INVALID_REQUEST, null);
        }
        User user = userDao.getEntityByMobile(mobile);
        if (user == null || !id_card.equals(user.getUserCard())) {
            return new BaseResult(false, "身份证号码手机号码不匹配");
        }
        if (!checkVerifyCode(mobile, verification_code, GlobalConstant.SMS_BIZ_CODE_VERIFY)) {
            return new BaseResult(false, "验证码验证失败", GlobalConstant.ERROR_TYPE_BUSINESS);
        }
        return new BaseResult();
    }

    /**
     * 判断用户是否开户
     *
     * @param userId
     * @return
     */
    @Override
    public boolean checkAccountOpen(Long userId, Long profileId) {

        User userEntity = getUser(userId);
        if (userEntity == null) {
            return false;
        }
        OrganProfile organProfile = new OrganProfile();
        if (userEntity.getIsOrg()) {
            organProfile = organProfileService.qryByProfileId(profileId);
            if (organProfile == null) {
                return false;
            } else {
                return EqualsUtil.equals(organProfile.getState().intValue(), GlobalConstant.ORGAN_STATE_PASS);
            }
        }
        String externalClientId;
        if (userEntity.getIsOrg()) {
            externalClientId = organProfile.getExternalClientId();
        } else {
            externalClientId = userEntity.getExternalClientId();
        }

        if (StringUtil.isEmpty(externalClientId)) {
            // 未开户
            return false;
        } else {
            // 获取用户银行卡
            BaseListResult listResult = queryService.queryAccountBanks("", externalClientId, "",
                GlobalConstant.MAX_REQUEST_NUM, 1, 1, "1");
            if (!listResult.getSuccess()) {
                throw new BaseException(listResult.getErrorCode(), listResult.getErrorMessage());
            }

            List<BankModel> banks = ((BankListResult) listResult).getBanks();
            if (banks == null || banks.size() == 0) {
                // 未开户
                return false;
            } else {
                // 判断是否开户
                int counter = 0;
                int app = 0;
                for (BankModel bankModel : banks) {
                    if (bankModel.getCapitalMode().equals(GlobalConstant.CAPITAL_MODE_COUNTER)) {
                        counter = counter + 1;
                    } else if (!StringUtil.isEmpty(bankModel.getCapitalMode())) {
                        app = app + 1;
                    }
                }

                if (app > 0) {
                    // APP已开户
                    return true;
                } else if (counter > 0) {
                    // 柜台已开户
                    return true;
                } else {
                    // 未开户
                    return false;
                }
            }
        }
    }


    /**
     * 判断用户 是否已经填写支行信息
     * 只考虑了单卡   但是因为 后续的用户都不会出现这样的情况  所以没有问题
     */
    @Override
    public BankModel getChangeBranch(Long userId) {
        List<UserBank> userBanks = userBankDao.getListByUserId(userId);
        BankModel bankModel = new BankModel();
        bankModel.setChangeBranch(false);
        if (!userBanks.isEmpty()) {
            for (UserBank userBank : userBanks) {
                if (!"1".equals(userBank.getCapitalMode()) && Strings.isNullOrEmpty(userBank.getBankBranchName())) {
                    bankModel.setBranchBank(userBank.getBranchbank() == null ? "" : userBank.getBranchbank());
                    bankModel.setBranchBankName(userBank.getBankBranchName() == null ? "" : userBank.getBankBranchName());
                    bankModel.setBankName(userBank.getBankName());
                    bankModel.setBankCode(userBank.getBankCode());
                    bankModel.setUserBankNo(userBank.getUserBankNo());
                    bankModel.setCapitalMode(userBank.getCapitalMode());
                    bankModel.setTradeAccount(userBank.getExternalTradeAccount());
                    bankModel.setChangeBranch(true);
                    break;
                }
            }
        }
        return bankModel;
    }

    @Override
    public void updateAllUsersSysMessageCounts() {
        userDao.updateAllUsersSysMessageCounts();
    }

    @Override
    public void updateAllUsersSys() {
        userDao.updateAllUsersSys();
    }

    @Override
    public void updateChinaTax(Long userId){ userDao.updateChinaTax(userId); }
}
